Part Number: EK-LM4F120XL
Hi, I have the following setup: Wheel-encoders connected to INT_GPIOC and INT_GPIOD (left wheel interrupts C and right wheel interrupts D) and INT_TIMER2A interrupt increasing counter counting seconds since init. The purpose is that each time interrupt corresponding to wheel-encoder fires it generates a message containing time since init and the information about the wheel side and directions and send it through UART forward. The problem is that in some cases the time stamps of the events seems to be in the wrong order and this seems to happen every time the TIMER_INTERRUPT_FIRES i.e, one second is elapsed (see example sequence below) . I suspect this is related to interrupts overlapping each other but I'm not sure how to fix it? I would also like to move the UART sending routine (serial_write_message) to main loop away from the interrupt. However in this case I think I should block GPIOC and GPIOD interrupts firing before the serial_write_message_is completed, but not to loose them , i.e., something like below, but I'm not sure if it is possible to queue the interrupts for time of execution in main code? I would appreciate any suggestions to solve the problem.
Pseudo code sending the message through UART in main code instead of interrupt:
while(1) { //flag indicating new message if(new_message) { //queue interrupt routines generating new_message_string until old message is written to UART (but does not loose the interrupt) block_GPIO_interrupts(); //new_message_string contents are set in interrupt routine serial_write_message(new_message_string);
//old message written new messages can be accepted from interrupts unblock_GPIO_interrupts(); new_message = 0; } }
Example sequence of corrupted events
0 117.908203 0 1
0 117.956008 1 1
0 117.960891 0 1
0 117.999351 1 1
0 118.4722 0 1
0 118.56480 0 1
0 118.59448 1 1
0 118.102294 0 1
0 118.103828 1 1
0 118.156608 0 1
0 118.163978 1 1
0 118.202339 0 1
0 118.206573 1 1
The actual code generating and implementing the interrupts:
static void init_interrupts(){ GPIOPinIntEnable(GPIO_PORTD_BASE, input1); GPIOPinIntEnable(GPIO_PORTC_BASE, input2); IntEnable(INT_GPIOD); IntEnable(INT_GPIOC); IntEnable(INT_TIMER2A); TimerIntEnable(TIMER2_BASE, TIMER_TIMA_TIMEOUT); IntMasterEnable(); TimerEnable(TIMER2_BASE, TIMER_A); } void system_time() { TimerIntClear(TIMER2_BASE, TIMER_TIMA_TIMEOUT); seconds_since_init = seconds_since_init + 1; } void IntGPIOd(void){ if(!GPIOPinRead(GPIO_PORTD_BASE, input1) && left_high){ return; } else if(GPIOPinRead(GPIO_PORTD_BASE, input1) && !left_high) { return; } left_high = GPIOPinRead(GPIO_PORTD_BASE, input1) > 0 ? 0 : 1; int wheel = 0; int wheel_dir = 1; char rover_direction = motor_get_direction(); if(rover_direction == 'f') { wheel_dir = 1; } else if(rover_direction == 'b') { wheel_dir = 0; } else if(rover_direction == 'l') { wheel_dir = 0; } else if(rover_direction == 'r') { wheel_dir = 1; } GPIOPinIntClear(GPIO_PORTD_BASE, input1); float realtime = seconds_since_init + (float)(SysCtlClockGet() -1 - TimerValueGet(TIMER2_BASE, TIMER_A)) / ((float) SysCtlClockGet()); char message[80]; int message_len = eb_sprintf(message, "%d %f %d %d\n", 0, realtime, wheel, wheel_dir); serial_write_message(message, message_len); }