chipKIT® Development Platform

Inspired by Arduino™

Faster Ping)))

Created Fri, 26 Apr 2013 22:25:46 +0000 by tsalzmann


tsalzmann

Fri, 26 Apr 2013 22:25:46 +0000

Hi, I'm testing now four parallax ultrasonic sensors with a complex robot (that already require a lot from my max32) and I'm very worried with them. They are very slow. Not the sensor itself but the programming (pulseIn() function).

This is my actual program for the sensor:

class UltraSound
{
private:
  long dist;
  int _port;
public:
  void SetPort(int port);
  long read();
};

void UltraSound::SetPort(int port)
{
  _port = port;
}

long UltraSound::read()
{
  pinMode(_port, OUTPUT);
  digitalWrite(_port, LOW);
  delayMicroseconds(2);
  digitalWrite(_port, HIGH);
  delayMicroseconds(5);
  digitalWrite(_port, LOW);

  pinMode(_port, INPUT);
  long duration = pulseIn(_port, HIGH);

  dist = duration / 29 / 2;
  return dist;
}

UltraSound ultra;

void setup()
{
  Serial.begin(9600);
  ultra.SetPort(75);
}

void loop()
{
  Serial.println(ultra.read());
}

Is there any way I can make it much more faster? I tried it with a library I found for the Arduino (with interrupts) but it's imppossible for me to convert it to the max32. You can find the library here: [url]https://code.google.com/p/arduino-new-ping/[/url]. By the way, if you can convert it so that it works with the max32 I would really appreciate it :roll:

Thanks in advance


george4657

Sat, 27 Apr 2013 00:20:31 +0000

I did a test using the following code in the loop function:

// test digitalWrite three times digitalWrite(4, HIGH); // set the LED on digitalWrite(4, LOW); // set the LED off digitalWrite(4, HIGH); // set the LED on digitalWrite(4, LOW); // set the LED off digitalWrite(4, HIGH); // set the LED on digitalWrite(4, LOW); // set the LED off

// test direct write to bit LATCSET = 1 << 14; //C14 High LATCCLR = 1 << 14; //C14 Low LATCSET = 1 << 14; //C14 High LATCCLR = 1 << 14; //C14 Low LATCSET = 1 << 14; //C14 High LATCCLR = 1 << 14; //C14 Low

Looking at result on my scope I found: digitalWrite HIGH/LOW had a pulse rate of 1.4us = 714 KHz LATCSET/CLR had a pulse rate of 25ns = 40MHz = 56 times faster The problem is you have to know the port you are writing, not the number on the board.

I wrote a test function:

void SetPort(char cPort, int pinNum) { switch (cPort) { case 'C': LATCSET = 1 << pinNum; // High LATCCLR = 1 << pinNum; // Low break; // add other ports as needed default: break; } This gave about 25 MHz pulse There is also a LATxINV |( x = port) to invert a pin in one step


tsalzmann

Sat, 27 Apr 2013 14:39:38 +0000

Ok, now I can write a digital port much more faster. But how can I read it from any digital port using registers (I have more than 24 sensors that use digitalRead() every frame) ?


george4657

Sat, 27 Apr 2013 15:34:15 +0000

I would think reading port B would be: int x; x = PORTB;

reading single bit

x = PORTB &amp; 1&lt;&lt; 14; // read bir 14 Port B

Have not tried it but it does compile


dangeljs

Sat, 27 Apr 2013 16:01:14 +0000

I have some code that works with the HR-SC04 shown in your link, that shouldn't slow you program down much, but it comes with some drawbacks.

1)I used the hardware capture module, so it won't be compatible with arduino if you want to transfer the code back.

2)Also it means that you are forced to use on of the Input Capture (IC) pins and you don't have the flexibility of choosing which ever pin you wan't.

3)(optional) I used a PWM to trigger it consistently so that you don't have to use processing cycles to trigger the ping sensor...which has similar drawbacks as above.

4)I use an interrupt to handle some of the capturing in the background and any overflows of the timer.

  1. I'm not sure that the Parralax Ping sensor is the same as the HR-SC04, which has 4 pins and in particular one for trigger and one for echo.

The advantage is that you spend less time waiting on processing the signal and more time doing the other work you want to do thanks to the peripherals onboard.

If you're interested let me know and I'll dig up the code (haven't used it in a while).

Regards,

Jason


tsalzmann

Sat, 27 Apr 2013 17:53:36 +0000

I would really appreciate it if you could give me the code. The parallax ping sensor is almost the same. The only difference is that it has only 3 pins. Echo and trigger are on the same pin.


tsalzmann

Sat, 27 Apr 2013 18:09:30 +0000

Is there any place I can see the PORT (PORTA, PORTB etc) and the bit to shift so I can change the value of a corresponding known digital port number on the max32?


dangeljs

Sat, 27 Apr 2013 19:02:26 +0000

Here is my code. I had to strip it from another project and put it into a stand alone usable form.

What you need to know:

1)This was written for an UNO32, so you will need to identify which pins relate to OC5 and IC1. If you have the pin mappings from Digilant you will be able to find them.

2)Since you don't have a seperate trigger pin you won't be able to use the OC5, and will have to incorportate your own form of starting the ping (which will have to change the pin from an input to output and handle the delay of 10us or whatever it is).

  1. It is using Timers 2 and 3 in 32bit mode for the interrupt and also the timer for the IC.

Hope this works for your ping, or at least gives you some code to spark your own ideas.


tsalzmann

Sat, 27 Apr 2013 19:47:43 +0000

Thank you very much!!! :)


george4657

Sat, 27 Apr 2013 21:09:57 +0000

"Is there any place I can see the PORT (PORTA, PORTB etc) and the bit to shift"

Digilent reference manual for the Max32 has a list. starting at page 12 For example: ChipKIT Pin# 4 PIC Siignal SOSCO/T1CK/CN0/RC14 = pin functions Ports are R + Port letter + pin# RC14 = Port C pin 14 RB3 = Port B pin 3 etc You can see that a pin can have several functions. That is why it's not as safe to use the direct reading/writing of ports.


tsalzmann

Sat, 27 Apr 2013 22:29:14 +0000

I just saw that RX and TX should never be changed (input or output). In which port and bit are they?


tsalzmann

Sun, 28 Apr 2013 00:50:35 +0000

One more question. You just said that it is not safe to directly read or write on a certain port using registers. But how I said, I have 24 identical digital sensors that need to be read every frame using digitalRead(). Here is the code:

int SensorPorts[] = {42, 40, 38, 36, 34, 32, 30, 28, 26, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 52, 50, 48, 46, 44};

int count = 0;

void setup(){}

void loop(){
    for(int i = 0; i &lt; 24; i++){
        if(digitalRead(sensor[i].p) == 0)
        {
           count++;
        }
    }
}

Actually the program is a little bit more complicated. It actually reads how many times the sensor gives LOW in 30ms and then transfers it to the sensor's read value.

Anyway, can I still use registers to safely read them? And how would it look like?


mikes

Sun, 28 Apr 2013 18:21:38 +0000

As long as you set the pinMode to output first writing to the port should work fine and reading always is safe but it will return the value the pin is set to if the pin is designated as output.

//with a jumper between 13 and 12 both reads match
unsigned short int val;

void setup()
{
  pinMode(13,OUTPUT); //RG6 //these could be done with registers also
  pinMode(12,INPUT); //RB7  //but using pinMode is easier
  Serial.begin(115200);
}

void loop()
{
  PORTGSET = 0x40; //7th bit over 0-6
  delay(250);
  val=PORTG;
  Serial.print("Port G6: ");
  Serial.println((val&amp;0x40)&gt;0,DEC); //always one
  Serial.print("Port G7: ");
  Serial.println((val&amp;0x80)&gt;0,DEC); //one if input is high or floating
  PORTGCLR = 0x40; 
  delay(250);
  val=PORTG;
  Serial.print("Port G6: ");
  Serial.println((val&amp;0x40)&gt;0,DEC); //always zero
  Serial.print("Port G7: ");
  Serial.println((val&amp;0x80)&gt;0,DEC); //one if input is low
}

george4657

Sun, 28 Apr 2013 18:47:09 +0000

"I just saw that RX and TX should never be changed (input or output). In which port and bit are they?" Pins 0 and 1 are the RX/TX pins and they are connected to the serial port so they should not be used for anything else. They are ports F2 and F8

A place to look up pin vs port number is this file "mpide\hardware\pic32\variants\Max32\Board_Data.c"

const uint16_t digital_pin_to_timer_PGM[] = { _IOPORT_PG, // 29 RG7 _IOPORT_PG, // 43 RG8 _IOPORT_PG, // 50 RG7 _IOPORT_PG, // 51 RG8

You will see that pin 50 and 29 are port G7 and pin 51 and 43 are port number G8. My analysis shows this is true in master mode only, in slave mode pins 50 and 43 are Port G8 and pins 51 and 29 are port G7 This means you need to be in slave mode to use pin 50 and 29 With no pins on master/slave jumper pins 50 and 51 are not connected to anything.

A mike said if reading port using digitalRead() works doing direct read of port should also work. The fastest way to read all the ports would be to not use a loop but read in 24 steps if( PORTB & 1<< 12) ++count; // Port B -12 = PIN 42 ..... one line per port ..... etc if( PORTA & 1<< 10) ++count; // Port A-10 = PIN 44


tsalzmann

Sun, 28 Apr 2013 20:07:02 +0000

Ok, I will try it later. Thank you very much!!