Execution time of a while loop in Arduino Due doesn't match what expected - time

I wrote the following infinite loop consisting principally of five high-level instructions and ran it on an Arduino Due. Assuming one clock cycle per instruction I was expecting the LED to flash about every 5/6 second. Instead the time is above 30 seconds. Is there something slowing down the execution of this code?
#define LED_PIN 13
/////////////////////////////////////////////////////////////////////////
void setup()
{
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
/////////////////////////////////////////////////////////////////////////
noInterrupts();
}
/////////////////////////////////////////////////////////////////////////
void loop()
{
int cnt = 0;
/////////////////////////////////////////////////////////////////////////
noInterrupts();
while(true) // infinite loop
{
if(cnt == 0) // if cnt == 0 turn off led
{
interrupts();
digitalWrite(LED_PIN, LOW);
noInterrupts();
}
// clock rate 84000000 cycles per second
if(cnt == VARIANT_MCK) // if cnt is equal to clock rate flash on led
{
interrupts();
delay(10);
digitalWrite(LED_PIN, HIGH);
delay(10); // turn on led for a small amount of time
noInterrupts();
cnt = - 1; // reset counter
}
cnt ++ ; // increment counter
}
}
/////////////////////////////////////////////////////////////////////////

I were expecting the number of seconds roughly shows, how many clock ticks it takes to do
while (true) {
cnt++;
if (cnt == 0) {/* signalTheStart(); */}
if (cnt == VARIANT_MCK) {/* signalTheEnd(); */}
}
One 32-bit int increment, two failing int comparisons, and a jump back.
Not sure how often the variable is moved to / from memory and how a comparison with a 32 bit constant (?) is actually performed, and I do not know the ARM internals. But I agree, 30 ticks is a bit more than I expected. I guess by 5/6you mean "five or six" and not a bit less than one, but both interpretations are too optimistic.
Michael Zhilin's hint "Check assembler code" from the compiled binary is the way to go...
And, why do you need that? You already noticed that you need to inhibit interrupts, so this measurement is not applicable to real world scenarios at all...

Writing the code in assembler solved the problem. By comparing the on-off period of the led, the compiler generate about ten time the instructions i wrote directly in assembler.

Related

how to flush write to raspberry pi gpio pins

I have a program written in C++ on a Raspberry Pi 3. I mmap /dev/gpiomem to access the GPIO registers directly in user mode. Here is my function to write to output pins:
static uint32_t volatile *gpiopage; // initialized by mmap() of /dev/gpiomem
static uint32_t lastretries = 0;
void PhysLib::writegpio (uint32_t value)
{
uint32_t mask = 0xFFF000; // [11:00] input pins
// [23:12] output pins
// all the pins go through an inverter converting the 3.3V to 5V
gpiopage[GPIO_CLR0] = value;
gpiopage[GPIO_SET0] = ~ value;
// sometimes takes 1 or 2 retries to make sure signal gets out
uint32_t retries = 0;
while (true) {
uint32_t readback = ~ gpiopage[GPIO_LEV0];
uint32_t diff = (readback ^ value) & mask;
if (diff == 0) break;
if (++ retries > 1000) {
fprintf (stderr, "PhysLib::writegpio: wrote %08X mask %08X, readback %08X diff %08X\n",
value, mask, readback, diff);
abort ();
}
}
if (lastretries < retries) {
lastretries = retries;
printf ("PhysLib::writegpio: retries %u\n", retries);
}
}
Apparently there is some internal cache or something delaying the actual updating of the pins. So I'm wondering if there is some magic MRC or MCR or whatever that I can put so I don't have to read the pins to wait for the update to actually occur.
I'm quite sure this is happening because this code is part of a loop:
while (true) {
writegpio (0x800000); // set gpio pin 23
software timing loop for 1uS
writegpio (0); // clear gpio pin 23
software timing loop for 1uS
}
Sometimes Linux timeslices during the software timing loops on me and I get a delay longer than 1uS, which is ok for this project. Before I put in the code that loops until it reads the updated bit, sometimes the voltage on the pin stays high for longer than 1uS and is then low for correspondingly less than 1uS, or vice versa, implying that there is a total of 2uS delay for the two timing loops but the update of the actual pin is being delayed by the hardware. After inserting the corrective code, I always get at least 1uS of high voltage and 1uS of low voltage each time through the loop.

How to achieve a high sampling speed using an ADC with Raspberry Pi?

So, I am using the LTC 2366, 3 MSPS ADC and using the code given below, was able to achieve a sampling rate of about 380 KSPS.
#include <stdio.h>
#include <time.h>
#include <bcm2835.h>
int main(int argc, char**argv) {
FILE *f_0 = fopen("adc_test.dat", "w");
clock_t start, end;
double time_taken;
if (!bcm2835_init()) {
return 1;
}
bcm2835_spi_begin();
bcm2835_spi_setBitOrder(BCM2835_SPI_BIT_ORDER_MSBFIRST);
bcm2835_spi_setDataMode(BCM2835_SPI_MODE0);
bcm2835_spi_setClockDivider(32);
bcm2835_spi_chipSelect(BCM2835_SPI_CS0);
bcm2835_spi_setChipSelectPolarity(BCM2835_SPI_CS0, LOW);
int i;
char buf_[0] = {0x01, (0x08|0)<<4, 0x00}; // really doesn't matter what this is
char readBuf_0[2];
start = clock();
for (i=0; i<380000; i++) {
bcm2835_spi_transfernb(buf_0, readBuf_0, 2);
fprintf(f_0, "%d\n", (readBuf_0[0]<<6) + (readBuf_0[1]>>2));
}
end = clock();
time_taken = ((double)(end-start)/CLOCKS_PER_SEC);
printf("%f", (double)(time_taken));
printf(" seconds \n");
bcm2835_spi_end();
bcm2835_close();
return 0;
}
This returns about 1 second every time.
When I used the exact same code with LTC 2315, I still get a sampling rate of about 380 KSPS. How come? First of all, why is the 3 MSPS ADC giving me only 380 KSPS and not something like 2 MSPS? Second, when I change the ADC to something that's about 70% faster, I get the same sampling rate, why is that? Is that the limit of the Pi? Any way of improving this to get at least 1 MSPS?
Thank you
I have tested a bit of the Raspberry Pi SPI and found out that the spi has some overheads. In my case, I tried pyspi, where one byte seems to take at least 15us, and 75us between two words ( see these captures). That's slower than what you measure, so good for you!
Increasing the SPI clock changes the length of the exchange, but not the overheads. Hence, the critical time doesn't change, as the overhead is the limiting factor. 380ksps means 2.6us by byte, that may be well close to your overhead ?
The easier way to improve the ADC speed would be to used parallel ADCs instead of serial - it has the potential to increased overall speed to 20Msps+.

Use libpic30.h with PIC32

Now I'm developing my own port to PIC32 and I need to use libpic30.h library. I have been reading about it and looking for the same library to PIC32 (starter kit III PIC32MX450/470 MCU) and I think it doesn't exist. That's right? If it exist wonderful!
libpic30.h code:
https://code.google.com/p/uavfirmware/source/browse/UAVFirmware/include/libpic30.h?r=1db3ec8e9015efb837b0d684c98204317ea2efd5
In this case, libpic30.h is not comptabible with PIC32 right?
I don't know, very well, how is the best way to do this port in this case?... I'm very lost!
Thanks for you knowledge!! ;)
Yeah first off you can't use libpic30.h. The compiler shouldn't let you use it easily. You'll want to use xc.h and follow that through for your appropriate PIC32 device. I'm not sure where the delay function lies but there is one somewhere down in there close to what you want. If you can't find it. Look in Tick.c for the TCP/IP legacy libraries there is a written delay in there for 32 bit devices.
void SSTDelay10us(U32 tenMicroSecondCounter)
{
volatile S32 cyclesRequiredForEntireDelay;
int clock;
clock = 80000000;
if (clock <= 500000) //for all FCY speeds under 500KHz (FOSC <= 1MHz)
{
//10 cycles burned through this path (includes return to caller).
//For FOSC == 1MHZ, it takes 5us.
//For FOSC == 4MHZ, it takes 0.5us
//For FOSC == 8MHZ, it takes 0.25us.
//For FOSC == 10MHZ, it takes 0.2us.
}
else
{
//7 cycles burned to this point.
//We want to pre-calculate number of cycles required to delay 10us *
// tenMicroSecondCounter using a 1 cycle granule.
cyclesRequiredForEntireDelay = (S32)(clock / 100000) * tenMicroSecondCounter;
//We subtract all the cycles used up until we reach the
//while loop below, where each loop cycle count is subtracted.
//Also we subtract the 5 cycle function return.
cyclesRequiredForEntireDelay -= 24; //(19 + 5)
if (cyclesRequiredForEntireDelay <= 0)
{
// If we have exceeded the cycle count already, bail!
}
else
{
while (cyclesRequiredForEntireDelay > 0) //19 cycles used to this point.
{
cyclesRequiredForEntireDelay -= 8; //Subtract cycles burned while doing each delay stage, 8 in this case.
}
}
}
}

Keeping Track of Time With Mbed

I'm using the mbed platform to program a motion controller on an ARM MCU.
I need to determine the time at each iteration of a while loop, but am struggling to think of the best way to do this.
I have two potential methods:
1) Define how many iterations can be done per second and use "wait" so each iteration occurs after a regular interval. I can then increment a counter to determine time.
2) Capture system time before going into the loop and then continuously loop, subtracting current system time from original system time to determine time.
Am I thinking along the right tracks or have I completely missed it?
Your first option isn't ideal since the wait and counter portions will throw off the numbers and you will end up with less accurate information about your iterations.
The second option is viable depending on how you implement it. mbed has a library called "Timer.h" that would be an easy solution to your problem. The timer function is interrupt based (using Timer3 if you use a LPC1768) you can see the handbook here: mbed .org/ handbook /Timer. ARM supports 32-bit addresses as part of the Cortex-M3 processors, which means the timers are 32-bit int microsecond counters. What that means for your usability is that this library can keep time up to a maximum of 30 minutes so they are ideal for times between microseconds and seconds (if need more time than that then you will need a real-time clock). It's up to you if you want to know the count in milliseconds or microseconds. If you want micro, you will need to call the function read_us() and if you want milli you will use read_ms(). The utilization of the Timer interrupts will affect your time by 1-2 microseconds, so if you wish to keep track down to that level instead of milliseconds you will have to bear that in mind.
Here is a sample code for what you are trying to accomplish (based on an LPC1768 and written using the online compiler):
#include "mbed.h"
#include "Timer.h"
Timer timer;
Serial device (p9,p10);
int main() {
device.baud(19200); //setting baud rate
int my_num=10; //number of loops in while
int i=0;
float sum=0;
float dev=0;
float num[my_num];
float my_time[my_num]; //initial values of array set to zero
for(int i=0; i<my_num; i++)
{
my_time[i]=0; //initialize array to 0
}
timer.start(); //start timer
while (i < my_num) //collect information on timing
{
printf("Hello World\n");
i++;
my_time[i-1]=timer.read_ms(); //needs to be the last command before loop restarts to be more accurate
}
timer.stop(); //stop timer
sum=my_time[0]; //set initial value of sum to first time input
for(i=1; i < my_num; i++)
{
my_time[i]=my_time[i]-my_time[i-1]; //making the array hold each loop time
sum=sum+my_time[i]; //sum of times for mean and standard deviation
}
sum = sum/my_num; //sum of times is now the mean so as to not waste memory
device.printf("Here are the times for each loop: \n");
for(i=0; i<my_num; i++)
{
device.printf("Loop %d: %.3f\n", i+1, my_time[i]);
}
device.printf("Your average loop time is %.3f ms\n", sum);
for(int i=0; i<my_num; i++)
{
num[i]= my_time[i]-sum;
dev = dev +(num[i])*(num[i]);
}
dev = sqrt(dev/(my_num-1)); //dev is now the value of the standard deviation
device.printf("The standard deviation of your loops is %.3f ms\n", dev);
return 0;
}
Another option you can use are the SysTick timer functions which can be implemented similar to the functions seen above and it would make your code more portable to any ARM device with a Cortex-Mx since it's based on the system timer of the microprocessor (read more here: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0497a/Babieigh.html). It really depends on how precise and portable you want your project to be!
Original source: http://community.arm.com/groups/embedded/blog/2014/09/05/intern-inquiry-95

ARDUINO Buzzer playing sound when it shouldn't

So I made this kind of a temperature/humidity sensor and decided to add a fire sensor feature. So it all works fine, right? No, I also decided I want a buzzer to that. Tested it, works well, so I thrown it into my project.
Started it up [project], lit up a lighter, works fine, LEDs blink, a text is shown, buzzer plays an alarm. But then, after the fire was out, the buzzer continued to play one of two tones, even though there was no fire. Here's the code, to make it all clear:
#include <LiquidCrystal.h>
#include <dht.h>
LiquidCrystal lcd(7, 6, 5, 4, 3, 2);
dht DHT;
#define FLAME 13
#define DHT11_PIN 8
#define ALARM A5
const int a9 = 9, a10 = 10, a11 = 11, a12 = 12;
byte z[8] = {
B00100,
B00000,
B11111,
B00001,
B00010,
B00100,
B11111,
B00000,
};
byte st[8] = {
0b00110,
0b01001,
0b01001,
0b00110,
0b00000,
0b00000,
0b00000,
0b00000,
};
void setup(){
lcd.begin(16, 2);
lcd.createChar(0, st);
lcd.createChar(1, z);
Serial.begin(9600);
pinMode((a9, a10, a11, a12), OUTPUT);
pinMode(FLAME, INPUT);
pinMode(ALARM, OUTPUT);
}
void loop() {
// Flame sensor code for Robojax.com
int fire = digitalRead(FLAME);// read FLAME sensor
if(fire == HIGH)
{
analogWrite(a9, 255);
analogWrite(a10, 255);
lcd.setCursor(5, 0);
lcd.print("Po");
lcd.print(char(1));
lcd.print("ar!");
tone(ALARM, 4300);
delay(150);
analogWrite(a9, 0);
analogWrite(a10, 0);
lcd.clear();
tone(ALARM, 3500);
delay(150);
} else {
lcd.createChar(0, st);
int chk = DHT.read11(DHT11_PIN);
lcd.home();
lcd.print("Temp.: ");
lcd.print(DHT.temperature);
if(DHT.temperature >= 20.00 && DHT.temperature < 25) {
analogWrite(a11, 255);
delay(750);
analogWrite(a11, 0);
delay(750);
} else if(DHT.temperature >= 25 && DHT.temperature < 30) {
analogWrite(a10, 255);
delay(250);
analogWrite(a10, 0);
delay(250);
} else if(DHT.temperature >= 30) {
analogWrite(a9, 255);
}
lcd.print(char(0));
lcd.print("C");
lcd.setCursor(0, 1);
lcd.print("Wilg.: ");
lcd.print(DHT.humidity);
if(DHT.humidity >= 45.00 && DHT.humidity < 60.00) {
digitalWrite(a12, HIGH);
delay(250);
digitalWrite(a12, LOW);
delay(250);
} else if(DHT.humidity >= 60.00) {
digitalWrite(a12, HIGH);
}
lcd.print(" %");
delay(750);
}
delay(200);
}
So, what I mean is that even though fire is changed from HIGH to LOW and other part of the code is executed, the buzzer continues to play.
What am I doing wrong?
Check the documentation for tone:
A duration can be specified, otherwise the wave continues until a call
to noTone().
So, you probably need to reset your tone on every loop beginning before checking the values of the sensors (or explicitly invoke notone on the LOW branch), or use the 3-arg version of tone.
I have no idea how tone and delay might interact, though.
I'd probably make the actual tone sounding routine its own task. The idea is that you would start the alarm task and then reset it when appropriate. But for now make sure your state is reset at the beginning of every loop, or each branch resets anything it has to explicitly, if tasks sound too advanced.
Make sure you learn the basic "print" debugging in the Arduino world. Simple write logging to the serial port where it can be read on the IDE is invaluable.
Finally: use functions! If you put everything in loop your programs will get unreadable as they grow. For example, if you have some state you want to reset every time (e.g., running tasks like tones, values, flags) then create an init() function that loop calls first so any given loop has good starting state.
Limitations of the Piezo Buzzer
Here are some things to consider when using the piezo buzzer:
You can’t use tone() while also using analogWrite() on pins 3 or 11

Resources