Timestamp at packet receive in serial 1 ISR

Status
Not open for further replies.

Franky_74

Member
I my code in my logger SW shord make a Timestamp every Time a Serial Frame Error is recognised - because i need this information - for this i use this code:

I use Arduino 1.05 r2 because i modify old project from 2014 an library parameters have changed since them.
ISR in Serial1.c

void uart0_error_isr (void)
{
uint8_t status, temp;
uint32_t count, current, istatus,microseconds;


__disable_irq();
current = SYST_CVR;
count = systick_millis_count;
istatus = SCB_ICSR; // bit 26 indicates if systick exception pending
__enable_irq();
//systick_current = current;
//systick_count = count;
//systick_istatus = istatus & SCB_ICSR_PENDSTSET ? 1 : 0;
if ((istatus & SCB_ICSR_PENDSTSET) && current > 50) count++;
current = ((F_CPU / 1000) - 1) - current;
microseconds = count * 1000 + current / (F_CPU / 1000000);
if (microseconds>microseconds_last) elapsed_microseconds = microseconds-microseconds_last;
else elapsed_microseconds = (0xFFFFFFFF + microseconds_last - microseconds);
elapsed_milliseconds = elapsed_microseconds/1000;
microseconds_last = microseconds;
/* Since the flag clearing mechanism will clear any flags in S1
* that are set, we have to save off the value of the status register
* and then check against the saved value to be able to detect all of
* the flags that were set (if you read the status register over and
* over again, then you'll only capture the first one that was set.
*/

/* Read and save the S1 value */
status = UART0_S1;

/* Check to see if a receiver overrun has been detected */
if (status & UART_S1_OR)
{
//printf("\nUART receiver overrun detected.\n");
num_or_errors++;




/* Read data register to clear the flag */
temp = UART0_D;
}

/* Check to see if the noise flag is set */
if (status & UART_S1_NF)
{
// printf("\nUART noise error detected.\n");
num_nf_errors++;

/* Read data register to clear the flag */
temp = UART0_D;
}

/* Check to see if a framing error was detected */
if (status & UART_S1_FE)
{
if (sum_rx_data > 0)
{
num_frame_posistion[num_frame_posistion_counter] = sum_rx_data;
sum_elapsed_milliseconds = elapsed_milliseconds + sum_elapsed_milliseconds;
num_frame_posistion_time[num_frame_posistion_counter] = sum_elapsed_milliseconds;

sum_rx_data = 0;

if (num_frame_posistion_counter >= num_frame_posistion_size)
{

num_frame_posistion_counter=0;
num_framing_errors=0;
}
else
{
num_frame_posistion_counter++;
num_framing_errors++;

}





}


/* Read data register to clear the flag */
temp = UART0_D;
UART0_BDH = (baudrate >> 13) & 0x1F;
UART0_BDL = (baudrate >> 5) & 0xFF;
// __enable_irq();
}

/* Check to see if a parity error was detected */
if (status & UART_S1_PF)
{
// printf("\nUART parity error detected.\n");
num_parity_errors++;

/* Read data register to clear the flag */
temp = UART0_D;
}

/* Check to see if a transmit buffer overflow was detected */
if (UART0_SFIFO & UART_SFIFO_TXOF)
{
// printf("\nUART transmit buffer overflow detected.\n");
num_txof_errors++;

/* Write 1 to flag to clear the flag */
UART0_SFIFO = UART_SFIFO_TXOF;
}

/* Check to see if a receiver underflow was detected */
if (UART0_SFIFO & UART_SFIFO_RXUF)
{
// printf("\nUART receiver buffer underflow detected.\n");
num_rxuf_errors++;

/* Write 1 to flag to clear the flag */
UART0_SFIFO = UART_SFIFO_RXUF ;
}
}
in the attacement the value of behavor of sum_elapsed_milliseconds is seen.
sometimes it seems to have a jump and later a glitch - can someone explain me why this happend and how i can write the code better?

In my old project the ISR is modified direct inside the Hardware file (serial1.c)
Can this also be done outside - because this is a one way solution - if i want to upgrade arduino or if i want to use a new teensyduino version - i must migrate it to the serial1.c of the new version.

every advice would be helpful for me....

Many thanks,
Frank Muenzner
 

Attachments

  • Teensy time logging.png
    Teensy time logging.png
    7 KB · Views: 109
Your overflow handling is buggy. Is there a reason, you are not using micros()?

This will properly handle overflow:
Code:
uint32_t microseconds_last = ...;
...

void uart0_error_isr(void) {
    uint32_t microseconds = micros();
    uint32_t elapsed_microseconds = microseconds - microseconds_last;
    microseconds_last = microseconds;
...
 
Many thanks to your explication, could you please explain more deep...
this is the micros function inside of pins_teensy.c

// the systick interrupt is supposed to increment this at 1 kHz rate
volatile uint32_t systick_millis_count = 0;

//uint32_t systick_current, systick_count, systick_istatus; // testing only

uint32_t micros(void)
{
uint32_t count, current, istatus;

__disable_irq();
current = SYST_CVR;
count = systick_millis_count;
istatus = SCB_ICSR; // bit 26 indicates if systick exception pending
__enable_irq();
//systick_current = current;
//systick_count = count;
//systick_istatus = istatus & SCB_ICSR_PENDSTSET ? 1 : 0;
if ((istatus & SCB_ICSR_PENDSTSET) && current > 50) count++;
current = ((F_CPU / 1000) - 1) - current;
return count * 1000 + current / (F_CPU / 1000000);
}


if you look on micros() - you can see - i have copy it with ligth modification to my ISR code.
i didnt call micros() from inside a isr because i didnt know exactly what happen if i call inside a ISR another function - will the necessary registers automaticly saved or should i do manually .
For this I would like to have debug capibility on teensy, if i can see the executed asm code i would know if the code uses a subcall.
If i understand the mircos code correct and your code then i ask me where the overflow is be handled, only by declaring of number formats?

Sorry if my knowledge need some help to go to next level...
Could you also say me if i can somewhere find the compiled asm code?

Many thanks for your help - i will try it and make a test over nigth.
 
The overflow of microseconds wont work:

Code:
if (microseconds>microseconds_last) elapsed_microseconds = microseconds-microseconds_last;
else elapsed_microseconds = (0xFFFFFFFF + microseconds_last - microseconds);

if all time counts are uint32_t then its enough to use

Code:
elapsed_microseconds = microseconds-microseconds_last;

The 32 bit unsigned arithmetic will handle the counter rollovers for you.
 
ARM Cortex allows standard functions to be ISRs. Calling other functions from an ISR works perfectly fine.

To get assembly code:
arm-none-eabi-objdump -d --demangle -C YOUR_COMPILED_SKETCH.elf > assembly.txt

arm-none-eabi-objdump is included with the toolchain, e.g. arduino/hardware/tools/arm/bin/arm-none-eabi-objdump.exe.
 
ok, at this time i get the code in assembly - because i had some trouble to understand the asm opcode - i used the mixed version (-S).
But i this help me only minimal.
Im Interested in understanding, but at this time i must solve my trouble with the datalogger.

For this i want to switch on an LED but inside an ISR this didnt seem to work....

at first i tried with DigitalWriteFast(PinNr,state) as this didnt work the CORE_PIN23_PORTSET = CORE_PIN23_BITMASK; command was tested- but it did'nt work. any sugestion - used code is at bottom....

could someone explain my why i could not toggle an LED?



/* Check to see if a framing error was detected */


if (status & UART_S1_FE)

{
// delayMicroseconds(20);
// digitalWriteFast(23, 1);
// digitalWriteFast(21, 1);
CORE_PIN21_PORTSET = CORE_PIN21_BITMASK;
CORE_PIN23_PORTSET = CORE_PIN23_BITMASK;
FrameLED_value =~ FrameLED_value;
if (sum_rx_data > 0)
{
num_frame_posistion[num_frame_posistion_write_counter] = sum_rx_data;
sum_rx_data = 0;

microseconds = micros();
elapsed_microseconds = microseconds - microseconds_last;
microseconds_last = microseconds;
sum_elapsed_milliseconds = sum_elapsed_milliseconds + elapsed_microseconds/1000;



num_frame_posistion_time[num_frame_posistion_write_counter] = sum_elapsed_milliseconds;

if ( num_frame_posistion_write_counter >= num_frame_posistion_read_counter) num_frame_packets_to_read = num_frame_posistion_write_counter -num_frame_posistion_read_counter;
else num_frame_packets_to_read = num_frame_posistion_counter_max - num_frame_posistion_read_counter + num_frame_posistion_write_counter;







if (num_frame_posistion_write_counter >= num_frame_posistion_counter_max)
{

num_frame_posistion_write_counter=0;

}
else
{
num_frame_posistion_write_counter++;


}





}


/* Read data register to clear the flag */
temp = UART0_D;
UART0_BDH = (baudrate >> 13) & 0x1F;
UART0_BDL = (baudrate >> 5) & 0xFF;
CORE_PIN23_PORTSET = CORE_PIN23_BITMASK;



// __enable_irq();
}
 
Please post sanely formatted code in CODE tags:
[CODE]your code[/CODE]

digitalWriteFast works fine in ISRs. Did you you configure the pins for OUTPUT?

You can use USB serial 'Serial.print()' for debug output in the ISR. It can crash / corrupt output, if it interrupts other USB serial output, but it works well enough for debugging purposes.
 
Serial print did'nt work... i get an error message:
C:\Users\Muenznef\Desktop\TeensyLogger_old\arduino-1.0.5-r2\hardware\teensy\cores\teensy3\serial1.c:738:4: error: 'Serial' undeclared (first use in this function)

the DigitalWriteFast works at this time - a strange thing happend in my ISR - i had modify the RWFIFO value from value 4 to 1 - because i need a timestamp the time difference from byte[n] to byte[n +1] of received byte so that i can see if a frame timout.
Code:
if (status & (UART_S1_RDRF | UART_S1_IDLE)) {
		__disable_irq();
		avail = UART0_RCFIFO;
		if (avail == 0) {
			// The only way to clear the IDLE interrupt flag is
			// to read the data register.  But reading with no
			// data causes a FIFO underrun, which causes the
			// FIFO to return corrupted data.  If anyone from
			// Freescale reads this, what a poor design!  There
			// write should be a write-1-to-clear for IDLE.
			c = UART0_D;
			// flushing the fifo recovers from the underrun,
			// but there's a possible race condition where a
			// new character could be received between reading
			// RCFIFO == 0 and flushing the FIFO.  To minimize
			// the chance, interrupts are disabled so a higher
			// priority interrupt (hopefully) doesn't delay.
			// TODO: change this to disabling the IDLE interrupt
			// which won't be simple, since we already manage
			// which transmit interrupts are enabled.
			UART0_CFIFO = UART_CFIFO_RXFLUSH;
			__enable_irq();
		} else {
			__enable_irq();
			digitalWriteFast(23, 0); 
			sum_rx_data = sum_rx_data + avail;
			
			head = rx_buffer_head;
			tail = rx_buffer_tail;
			elapsed_time_micros = micros();
			time_since_last_reception = elapsed_time_micros -last_reception_time_micros; // get value of last reception time in
			last_reception_time_micros = elapsed_time_micros;

if i set RWFIFO = 1 then i did'nt get a Frame Error but i dont know why?
 
Serial print did'nt work... i get an error message:
C:\Users\Muenznef\Desktop\TeensyLogger_old\arduino-1.0.5-r2\hardware\teensy\cores\teensy3\serial1.c:738:4: error: 'Serial' undeclared (first use in this function)
'Serial' is C++, so you can't use it from 'serial1.c'. You can either move the ISR to a .cpp file or use the low level stuff from 'usb_serial.h' (usb_serial_write).
 
Status
Not open for further replies.
Back
Top