Not Equals Operator not working when interrupts are enabled on PIC32 [closed] - c

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I am currently trying to parse a string received via UART from a GPS module on a PIC32MZ2048EFG100 micro-controller via a UART receive interrupt protocol. I am using MPLAB X IDE v4.10 and XC32 v2.05 for my IDE and compiler.
When I enabled the UART4 receive interrupt, the != operator stops functioning as it should. I have a block of code within my main function that should never be executed, but yet it is.
I have narrowed it down to enabling interrupts being the problem. If I comment out all working code in my ISR, I still face the issue of myCounter being incremented.
Here is the code I have in my main function.
int myCounter = 0;
void main ( void ){
hal_sys_init();
hal_uart4_init();
gps_init();
//Setup interrupt
asm volatile("di"); //Disable all interrupts
asm volatile("ehb"); //Disable all interrupts
INTCON = 0; //Clear interrupt control register
IEC0 = 0;
IEC1 = 0;
IEC2 = 0;
IEC3 = 0;
IEC4 = 0;
IEC5 = 0;
IEC6 = 0;
INTCONbits.MVEC = 1; //Enable multi-vectored interrupts
IFS5bits.U4RXIF = 0; //Clear interrupt flag
IPC42bits.U4RXIP = 1; //Set priority level to 7
IPC42bits.U4RXIS = 0; //Set sub-priority to 0
IEC5bits.U4RXIE = 1; //Enable interrupt
asm volatile("ei"); //Enable all interrupts
while(1){
int x = 0;
if(x != 0){
myCounter++; //Should never be executed
}
}
}
When running this code on my PIC with interrupts enabled, myCounter gets incremented.
Here is the code for my interrupt service routine.
void __ISR(_UART4_RX_VECTOR, ipl7SRS) UART4_Interrupt(void) {
while (U4STAbits.URXDA) {
char c = U4RXREG;
if (c == '\n') {
currentLine[--lineIndex] = 0; //Overwrite /r as null terminator for string
parseStringFlag = 1;
lineIndex = 0;
if (currentLine == buff_1) {
currentLine = buff_2;
previousLine = buff_1;
} else {
currentLine = buff_1;
previousLine = buff_2;
}
} else if (lineIndex < MAX_LINE_LENGTH) {
currentLine[lineIndex++] = c;
} else {
currentLine[--lineIndex] = c;
}
}
IFS5bits.U4RXIF = 0; //Clear interrupt flag
return;
}
Here is the basic ISR code that still makes myCounter increment.
void __ISR(_UART4_RX_VECTOR, ipl7SRS) UART4_Interrupt(void) {
while (U4STAbits.URXDA) {
char c = U4RXREG;
}
IFS5bits.U4RXIF = 0; //Clear interrupt flag
return;
}
What could be causing the code that should never be executed to execute? If I run the interrupt code in main with interrupts disabled the code works and the code that should never be executed is not executed.

Here:
if (c == '\n') {
currentLine[--lineIndex] = 0; //Overwrite /r as null terminator for string
If the first character received were \n and lineIndex is initialised zero, lineIndex will be decremeted from zero. Assuming it is unsigned, then lineIndex < MAX_LINE_LENGTH will be false and:
} else {
currentLine[--lineIndex] = c;
}
will run repeatedly until lineIndex is eventually decremented to MAX_LINE_LENGTH - 1 - stomping over a large swathe of memory - which is most likely what is happening in this case.
Suggest:
if( lineIndex != 0 && c == '\n' && )
{
currentLine[--lineIndex] = 0; //Overwrite /r as null terminator for
or:
if( c == '\n' )
{
if( lineIndex != 0 )
{
lineindex-- ;
}
currentLine[lineIndex] = 0; //Overwrite /r as null terminator for
depending on the semantics you require. It is not a given that the sending system uses CR+LF pairs for line-ends, and you should not assume that. The code should probably be further modified to check that the preceding character was indeed a CR before decrementing lineindex. An exercise for the reader.
And similarly for the final else:
}
else if( lineIndex != 0 )
{
currentLine[--lineIndex] = c;
}
or
}
else
{
if( lineIndex != 0 )
{
lineindex-- ;
}
currentLine[lineIndex] = c;
}
It is possible that the latter protection is not necessary, but the protection is useful perhaps for clarity and maintenance - it is defensive code - your call.
It may be a safer and more interrupt efficient design to have the ISR simply place any received character into a ring-buffer, and then deal with line-input outside of the interrupt context. You might increment a counter on every received \n and decrement it when \n were unbuffered so that the receiver will know how many lines are currently buffered for processing.

Related

receive/transmit over rs232 with arm lpc2148 on sparkfun logomatic

I am trying to program the logomatic by sparkfun, and yes I have used their forum with no responses, and having some issues. I am trying to send characters to the UART0 and I want the logomatic to respond with specific characters and not just an echo. For example, I send 'ID?' over the terminal (using RealTerm), and the logomatic sends back '1'. All it will so now is echo.
I am using c with programmers notepad with the WinARM toolchain. The following snippet is from the main.c file. I only included this, because I am fairly certain that this is where my problem lies
void Initialize(void)
{
rprintf_devopen(putc_serial0);
PINSEL0 = 0xCF351505;
PINSEL1 = 0x15441801;
IODIR0 |= 0x00000884;
IOSET0 = 0x00000080;
S0SPCR = 0x08; // SPI clk to be pclk/8
S0SPCR = 0x30; // master, msb, first clk edge, active high, no ints
}
Notice the rprintf_devopen function, below is from the rprintf.c file, and due to my mediocre skills, I do not understand this bit of code. If I comment out the rprintf_devopen in main, the chip never initializes correctly.
static int (*putcharfunc)(int c);
void rprintf_devopen( int(*put)(int) )
{
putcharfunc = put;
}
static void myputchar(unsigned char c)
{
if(c == '\n') putcharfunc('\r');
putcharfunc(c);
}
Now, below is from the serial.c file. So my thought was that I should be able to just call one of these putchar functions in main.c and that it would work, but it still just echoes.
int putchar_serial0 (int ch)
{
if (ch == '\n')
{
while (!(U0LSR & 0x20));
U0THR = CR; // output CR
}
while (!(U0LSR & 0x20));
return (U0THR = ch);
}
// Write character to Serial Port 0 without \n -> \r\n
int putc_serial0 (int ch)
{
while (!(U0LSR & 0x20));
return (U0THR = ch);
}
// Write character to Serial Port 1 without \n -> \r\n
int putc_serial1 (int ch)
{
while (!(U1LSR & 0x20));
return (U1THR = ch);
}
void putstring_serial0 (const char *string)
{
char ch;
while ((ch = *string))
{
putchar_serial0(ch);
string++;
}
}
I have tried calling the different putchar functions in main, also with the rprintf_devopen. Still just echoes. I have altered the putchar functions and still just echoes. I have tried just writing to the U0THR register in main.c and no luck. Keep in mind that I am still a student and my major is electrical engineering, so the only programming classes that I have taken are intro to c, and an intro to vhdl. I am more of a math and physics guy. I was working on this for an internship I was doing. The internship ended, but it just bugs me that I cannot figure this out. Honestly, working on this program taught me more that the c class that I took. Anyways, I appreciate any help that can be offered, and let me know if you want to see the entire code.
Below is an update to the question. This function is in main.c
static void UART0ISR(void)
{
char temp;
trig = 13; //This is where you set the trigger character in decimal, in this case a carriage return.
temp = U0RBR; //U0RBR is the receive buffer on the chip, refer to datasheet.
if(temp == query1[counter1]) //This segment looks for the characters "ID?" from the U0RBR
{ //query1 is defined at the top of the program
counter1++;
if(counter1 >= 3)
{
flag1 = 1; //This keeps track of whether or not query1 was found
counter1 = 0;
stat(1,ON);
delay_ms(50);
stat(1,OFF);
RX_in = 0;
temp = 0;
//rprintf("\n\rtransmission works\n");
putc_serial1(49);
}
}
if(temp == query2[counter2] && flag1 == 1) //This segment looks for "protov?" from the U0RBR, but only after query1 has been found
{
counter2++;
if(counter2 >= 7)
{
flag2 = 1; //This keeps track of whether or not query2 was found
counter2 = 0;
stat(1,ON);
delay_ms(50);
stat(1,OFF);
RX_in = 0;
temp = 0;
putc_serial1(49);
}
}
if(temp == stop[counter3]) //This if segment looks for certain characters in the receive buffer to stop logging
{
counter3++;
if(counter3 >= 2)
{
flagstop = 1; //This flagstop keeps track of whether or not stop was found. When the stop characters are found,
flag1 = 0; //the query1 and query2 flags will be reset. So, in order to log again these queries must be sent again
flag2 = 0; //this may seem obvious, but deserves mention.
counter3 = 0;
stat(1,ON);
delay_ms(500);
stat(1,OFF);
RX_in = 0;
temp = 0;
}
flagstop = 0; //Reset the stop flag in order to wait once again for the query 1&2
}
if(RX_in == 0)
{
memset (RX_array1, 0, 512); // This clears the RX_array to make way for new data
memset (RX_array2, 0, 512);
}
if(RX_in < 512 && flag1 == 1 && flag2 == 1) //We cannot log data until we see both flags 1 & 2 and after we see these flags,
{ //we must then see the trigger character "carriage return"
RX_array1[RX_in] = temp;
RX_in++;
if(temp == trig)
{
RX_array1[RX_in] = 10; // delimiters
log_array1 = 1;
RX_in = 0;
}
}
else if(RX_in >= 512 && flag1 == 1 && flag2 == 1) //This else if is here in case the RX_in is greater than 512 because the RX_arrays are defined to
{ //be of size 512. If this happens we don't want to lose data, so we must put the overflow into another register.
RX_array2[RX_in - 512] = temp;
RX_in++;
RX_array1[512] = 10; // delimiters
RX_array1[512 + 1] = 13;
log_array1 = 1;
if(RX_in == 1024 || temp == trig)
{
RX_array2[RX_in - 512] = 10; // delimiters
log_array2 = 1;
RX_in = 0;
}
}
temp = U0IIR; // have to read this to clear the interrupt
VICVectAddr = 0;
}

how can I escape from main while loop(C programming)?

I am trying to escape from the main loop if external stop key is pressed.
Currently, communicating AT32UC with ATmega128 through RS485 communication where START and STOP keys are implemented.
RS485 receiver interrupt is called if there is data to be processed in the receiver side where 0x10 = Start and 0x11 = Stop.
My problem is that start and stop keys are recognised well and main loop is continued if start and I would like to terminate the main loop if stop key is pressed.
So I've set the start flag and stop flag accordingly. But, I am struggling with stop(escape) implementation. Below is brief snippets of interrupt routine and main loop.
__attribute__((__interrupt__)) static void rs485RxInterrupt(void)
{
uint32_t data;
static char RxDatalength = 98;
data = AVR32_USART2.RHR.rxchr;
if(data & 0x00000100) // rs485 9 bit check
{
if((data & 0x000000ff) == 0x92) //dsp board address = 0x92
{
rxBuf[0] = data;
addr_flag = true;
rxInCtr = 1;
}
else
{
addr_flag = false;
return;
}
}
else if (addr_flag == true) // if 9 bit is checked
{
rxBuf[rxInCtr++] = data;
if(rxInCtr == 2) // command check
{
if(data < 0x80)
{
if(data==0x10) // start command
{
addr_flag = false; // reset addr flag
start_flag = true;
//RxDatalength = 0;
}
else if(data == 0x11) // stop command
break_flag = true;
}
else if(data >= 0x80)
//gpio_set_pin_high (AVR32_PIN_PA16);
RxDatalength = 3;
}
if ((rxInCtr == RxDatalength) || ((RxDatalength == 98) && (rxInCtr == rxBuf[2]+1))) // end of packet recognition
{
addr_flag = false;
start_flag = true;
}
}
}
int main()
{
......
while(!break_flag)
{
start_flag = false;
while(start_flag == false)
;
gpio_set_pin_high(AVR32_PIN_PA14);
delay_us(40);
gpio_set_pin_low(AVR32_PIN_PA14);
//****** loop stays at this point and I am not giving sync_flag high to
//continue so if I press stop, I want this thing to get out of the main
//while loop!!
// peaksRdy_flag = true;
// SendTx(peaks);
sync_flag = false; // synchronising main with start of the input
while(sync_flag == false)
;
envelopeIndex = 0;
for(uint32_t loop=0; loop<23; loop++) // looping 23 times to cover approx 4.5s
{
//reset counter
sampleCounter = 0;
samplingComplete = false;
//wait for sampling to finish, 256 samples
while (samplingComplete == false)
;
//gpio_set_pin_low(AVR32_PIN_PA15); // main loop indicator
windowing(x);
rms(x); // return ac_rms
//gpio_set_pin_low(AVR32_PIN_PA16); // fft indicator
fft_run(window); // return fft magnitude
//gpio_set_pin_high(AVR32_PIN_PA16);
peak_search(fft_mag);
envelope_output(envelope);
// Function to transmit analysed data through RS485 communication.
//SendTx(peaks);
sprintf(filtResult, "%04d %04d %04d %04d %04d\n", (int)peaks[loop][0], (int)peaks[loop][1], (int)peaks[loop][2], (int)peaks[loop][3],(int)ac_rms);
char *ptr = &filtResult[0];
do
{
c = *ptr;
ptr++;
usart_bw_write_char(&AVR32_USART2, (int)c);
// sendByte(c);
} while (c != '\n');
//gpio_set_pin_high(AVR32_PIN_PA15);
} // outer loop
sprintf(filtResult, "%04d\n", (int)duty);
char *ptr = &filtResult[0];
do
{
c = *ptr;
ptr++;
usart_bw_write_char(&AVR32_USART2, (int)c);
// sendByte(c);
} while (c != '\n');
break;
}//while
}//main
All your flags should be declared volatile.
eg:
volatile int start_flag, sync_flag /*,other_flag ... */;
else the compiler may optimise out checks for their value being changed by code outside the current block.

Stopping the program when reading data from UART

I have this simple code:
while(1){
char dolar = gps_get_char();//read char from uart
if ((dolar == '$') || (receive_dolar == 1)){
receive_dolar = 1;
gps_get_nmea(nmea_in, sizeof(nmea_in));
rozloz_nmea();
receive_dolar = 0;
}
/*control running program*/
if (tl2 == 1){ //flag button from interrupt
LCD ^= (1 << LED_ON_OFF);
tl2 = 0;
}
}
But when the GPS is turned off, so the program stops here:
char dolar = gps_get_char();//read char from uart
Where function gps_get_char();
char gps_get_char()
{
unsigned int in = 0;
do {
in = uart1_getc();
} while((in & UART_NO_DATA) || (in & UART_BUFFER_OVERFLOW));
return((char) in);
}
Any idea why the program is stopped?
Even if your current approach works, you are prone at losing UART data. You should really be using interrupts instead of polling. Have the interrupt fill a sufficiently large buffer and set a flag condition when it is done. Then, have the program process the buffer.
Cheers.

Confused with output to console, C / USB CDC / PIC18F2550

I have a problem that is probably a simple misunderstanding on my end.
I have a PIC18F2550 device with a USB CDC firmware. I would like to send it a command to output something to the console every second. However, it doesn't seem to work. I put in a loop to iterate for 5 seconds and display an output message every second, but it won't actually output anything. It passes through the 5 second loop until the end where it DOES display the final message after the loop was executed. It won't output anything DURING the loop though.
I included my entire ProcessIO function because I think it's important for this issue, but I commented where I placed the exact command I'm trying to figure out.
Thanks for any suggestions you guys have, I appreciate it. I'm a mechanical engineer trying to learn some embedded stuff.
/********************************************************************
* Function: void ProcessIO(void)
* Overview: This function is a place holder for other user
* routines. It is a mixture of both USB and
* non-USB tasks.
*******************************************************************/
void ProcessIO(void)
{
BYTE numBytesRead;
// User Application USB tasks
if((USBDeviceState < CONFIGURED_STATE)||(USBSuspendControl==1)) return;
if (USBUSARTIsTxTrfReady())
{
if((CDCattached == 0x01) && (CDCattachedcount == 2))
{
putUSBUSART((char*)"Text Message\r\n",49);
CDCTxService();
CDCattachedcount = 0;
CDCattached = 0x00;
}
numBytesRead = getsUSBUSART(USB_Out_Buffer, 64);
if (numBytesRead == 1)
{
if ((USB_Out_Buffer[0] == '\r')) //Received ENTER? Ues-> End of Command
{
if (pos >0)
{
command_recvd = 0x01;
Command[pos++] = '\0';
pos = 0;
}
}
else if ((USB_Out_Buffer[0] == 0x7F) || (USB_Out_Buffer[0] == 0x08))
{
if (pos > 0) pos--;
Command[pos] = '\0';
putUSBUSART ((char*) USB_Out_Buffer, 1);
}
else
{
Command[pos++] = USB_Out_Buffer[0];
putUSBUSART((char*) USB_Out_Buffer, 1);
Command[pos]='\0';
} //No:- Store Character to String
}
else if ((numBytesRead > 1))
{
strncpy(Command,USB_Out_Buffer,numBytesRead);
for(int indx = numBytesRead; indx < 64; indx++)
{
Command[indx]='\0';
}
pos = numBytesRead--;
command_recvd = 0x01;
Command[pos++] = '\0';
// putUSBUSART((char*) USB_Out_Buffer, 1);
pos = 0;
}
if (command_recvd == 0x01)
{
for (int aaa = 0; aaa <= 63; aaa++)
{
output_message[aaa]= '\0';
}
************** THIS IS WHERE MY TEST COMMAND IS ***************
if (strnicmp((char*) Command, (char*) "test", 4) == 0)
{
sprintf(output_message, "\r\nStarting loop...\r\n");
for int bbb = 0; bbb < 5; bbb++)
{
sprintf(output_message, "\r\nLooping...\r\n");
for (delayIndex = 0; delayIndex < 1000; delayIndex++)
{
__delay_ms(1);
}
}
sprintf(output_message, "\r\nLoop finished!\r\n");
}
else
{
invalidCommand:
sprintf(output_message, "\r\nInvalid Command Received. Please Retry.\r\n\0");
}
command_recvd = 0x00;
}
}
CDCTxService();
}
You should call putUSBUSART() and CDCTxService() before overwriting output_message
Also, CDCTxService() needs to be called frequently, so you have to call it during the delay loop.
for int bbb = 0; bbb < 5; bbb++)
{
sprintf(output_message, "\r\nLooping...\r\n");
putsUSBUSART(output_message);
for (delayIndex = 0; delayIndex < 1000; delayIndex++)
{
__delay_ms(1);
if(USBUSARTIsTxTrfReady()) {
sprintf(output_message, "\r\nInside inner loop\r\n");
putsUSBUSART(output_message);
}
CDCTxService();
}
}
Although that kind of bloking delays could work ( __delay_ms() ), a better aproach is to check for an ellapsed timer, or a timestamp. Something like:
for int bbb = 0; bbb < 5; bbb++)
{
sprintf(output_message, "\r\nLooping...\r\n");
putsUSBUSART(output_message);
timestamp = TickGet();
while (TickDiff(timestamp, TickGet()) < TICK_SECOND)
{
if(USBUSARTIsTxTrfReady()) {
sprintf(output_message, "\r\nInside inner loop\r\n");
putsUSBUSART(output_message);
}
CDCTxService();
}
}
TickGet and TickDiff are functions you have to implement yourself, however there are lots of examples on Microchip libraries
Short version: this approach won't work. You'll need to rethink how you're doing this.
USB devices cannot delay while processing events — they must be able to respond promptly to every request sent from the host. Delaying for as long as a second will typically cause the host to assume the device has been disconnected.
It's critical to understand here that the USB device model is based (almost) entirely around the host sending requests to a device, and the device replying. Devices cannot generate unsolicited responses.
Now, the reason you're not seeing the expected results here is because sprintf() doesn't send the results to the host; all it does is put a message into a buffer to prepare it to be sent back. Calling it multiple times overwrites that buffer, rather than sending multiple messages back.

how to give a parameters to a function in C [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
I don't know how to give a parameters to a function. I wrote a body, as you can see in my program below. Any answers and explanations appreciated!
#include <avr/io.h>
#include <stdint.h>
// Ceramic Resonator
#ifndef F_CPU
#define F_CPU 3686400 // 4MHz
#endif
// UART
#define UART_BAUD_RATE 9600
#define UART_BAUD_CALC(UART_BAUD_RATE,F_OSC) ((F_CPU)/((UART_BAUD_RATE)*16L)-1)
int decode( int rcv[i], ... ){ !!!
int returnValue;
if ((rcv[0] == rcv[1]) && (rcv[0] == rcv[2]) && (rcv[1] == rcv[2])){
returnValue = 0;
//return UDR0;
}
else if (rcv[1] != rcv[2] && (rcv[0] == rcv[1])){
returnValue = 1;
//UDR0 = 01;
}
else if (rcv[1] != rcv[2] && (rcv[0] == rcv[2])){
returnValue = 2;
//UDR0 = 02;
}
else if (rcv[0] != rcv[1] && (rcv[1] == rcv[2])){
returnValue = 3;
//UDR0 = 03;
}
return returnValue;
}
int main(void){
// USART
UBRR0H =(uint8_t) (UART_BAUD_CALC(UART_BAUD_RATE,F_CPU) >>8);
UBRR0L =(uint8_t) UART_BAUD_CALC(UART_BAUD_RATE,F_CPU);
UCSR0B = (1<<RXEN0) | (1<<TXEN0); // enable receiver and transmitter,
UCSR0C = (3<<UCSZ00); // 8 bit (default: asynchronous, no parity, 1 stop-bit)
DDRC = (1<<5); // set data direction register bit 5 to one, this means PC5 is configured as output
PORTC = (1<<5); // set output value of PC5 to High-Level (Source Current, 5V to ground)
// VARIABLES
//uint8_t get;
// PROGRAM
unsigned char code[3] = {'x','y','z'}; // Here you need to write your code
unsigned char rcv[3]={'0','0','0'}; // received data
int i = 0;
int retVal;
while(1){
i = 0;
for(i=0;i<=2;i++){
// wait for empty transmit buffer
//while (!(UCSR0A & (1<<UDRE0)));
// wait for data to be received
while (!(UCSR0A & (1<<RXC0)));
/* put data into buffer, sends the data*/
{
code[i]= UDR0 ;
}
//while(1) // forever
//{
PORTC ^= (1<<5); //this is for LED
// get received data from buffer
rcv[i] = code[i];
}
retVal = decode(int rcv[i], ... ); !!!
// wait for empty transmit buffer
while (!(UCSR0A & (1<<UDRE0)));
// put data into buffer, sends the data
/*if ((rcv[0] == rcv[1]) && (rcv[0] == rcv[2]) && (rcv[1] == rcv[2]))*/
UDR0 = retVal;
}
}
I like #Ari's answer but I feel like I should add that you can use variable parameter lists if that's what you want. You can find a good tutorial here, but this would probably be more work that you require.
Edit:
I just noticed the // Ceramic resonator comment so I'm guessing you're in an Embedded environment in which case I would strongly recommend a simple pointer like #Ari suggested. The variable parameter list might not be fully implemented on your architecture.
You should put pointer to an array and maybe size of it:
change:
int decode( int rcv[i], ...)
to
int decode( unsigned char* rcv)
and
retVal = decode(int rcv[i], ... ); !!!
to
retVal = decode(rcv); //rcv is a pointer

Resources