Important changes to forums and questions
All forums and questions are now archived. To start a new conversation or read the latest updates go to forums.mbed.com.
5 years, 10 months ago.
UART Communication Nucleo F072
Hi, i want to send all 2 seconds a command over uart. The answer I want to convert in an analog voltage. At the moment I just want to send the command and show the answer on the pc.
Uart communication
#include "mbed.h" #define size 512 Ticker write_ticker; Serial pc(USBTX,USBRX,9600); // UART to PC Serial easerial(A0, A1,115200); //Uart to device char rxBuff[size];//array to store unsigned int bufferWritingIndex = 0;//Writing Pointer unsigned int bufferReadingIndex = 0;//Reading Pointer void RxInterrupt(void); void readPc(void); void write_EA(void); int main(void) { // Set setting for UART easerial.format(8,Serial::None,1); pc.format(8,Serial::None,1); easerial.attach(&RxInterrupt, Serial::RxIrq); wait(1); // 1000 millisecond write_ticker.attach(&write_EA,1); // Write all second //easerial.printf("moti \r"); // Send command while(1) { readPc(); } } void RxInterrupt(void) { if(easerial.readable()) { rxBuff[bufferWritingIndex++]=easerial.getc(); if(bufferWritingIndex>=size) bufferWritingIndex=0; } } void readPc(void) { char rxByte; while(bufferReadingIndex != bufferWritingIndex) { rxByte = rxBuff[bufferReadingIndex++]; pc.putc(rxByte); // Write answer of device to pc if(bufferReadingIndex>=size) bufferWritingIndex=0; } } void write_EA() { easerial.printf("moti \r"); // Send command }
This answer i get at the pc, line 1,2,3 are right and the fourth line is wrong:
include the mbed library with this snippet
<\0><\0>moti <\r><\n> +00000<\r><\n> Ready.<\r><\n> m????m????m????m????
Why I don’t get every two seconds a response of the device? Why are most symbols of the last line wrong?
1 Answer
5 years, 10 months ago.
As far as I know printf still cannot be used from Interrupt context. You are calling write_EA() inside ISR via ticker. I would avoid trying to do any serial stuff inside ISR as most of it is wrapped in mutexes which cannot be used in ISR. And in general default implementation of printf() will block your whole program while it slowly putc() chars to the serial port at specified baud rate. You don't want to block your program in the ISR like that. ISR get in and get out as fast as possible.
Receiving in ISR can be made to work but you should use RawSerial class not plain Serial. RawSerial does not use mutexes. Interface is basically the same so just change the type.
Take a look at EventQueue. You can schedule functions to run at specific times or to be called at specific intervals (like your write_EA()). But it runs in a thread in normal context. It's very easy to use and avoids these interrupt problems. Use main to set stuff up but then do all your work in event queue thread to avoid any issues with parallel threads. And you can just keep throwing stuff at event queue with different timings and it will run everything at the right time in normal context. The call_in() method lets you adjust time between function calls on the fly as well.
I've not tested, but perhaps something like this:
#include "mbed.h" #define size 512 EventQueue event(10 * EVENTS_EVENT_SIZE); Thread event_thread(osPriorityNormal); Serial pc(USBTX,USBRX,9600); // UART to PC RawSerial easerial(A0, A1,115200); //Uart to device char rxBuff[size];//array to store unsigned int bufferWritingIndex = 0;//Writing Pointer unsigned int bufferReadingIndex = 0;//Reading Pointer void RxInterrupt(void); void readPc(void); void write_EA(void); int main(void) { // Set setting for UART easerial.format(8,Serial::None,1); pc.format(8,Serial::None,1); easerial.attach(&RxInterrupt, Serial::RxIrq); wait(1); // Read and Write happen in Event Thread in normal context event.call_every(1000, callback(write_EA)); event.call_every(10, callback(readPc)); // Start Event Queue Thread event_thread.start(callback(&event, &EventQueue::dispatch_forever)); while(1) { // Do nothing in main wait(1); } } void RxInterrupt(void) { if(easerial.readable()) { rxBuff[bufferWritingIndex++]=easerial.getc(); if(bufferWritingIndex>=size) { bufferWritingIndex=0; } } } void readPc(void) { char rxByte; while(bufferReadingIndex != bufferWritingIndex) { rxByte = rxBuff[bufferReadingIndex++]; pc.putc(rxByte); // Write answer of device to pc if(bufferReadingIndex>=size) { bufferWritingIndex=0; } } } void write_EA() { easerial.printf("moti \r"); // Send command }
Now it works until the rxbuff is full.
Uart communication
void RxInterrupt(void) { if(easerial.readable()) { bufferWritingIndex++; if(bufferWritingIndex>=size){ bufferWritingIndex=0; } rxBuff[bufferWritingIndex]=easerial.getc(); } } void readPc(void) { char rxByte; while(bufferReadingIndex != bufferWritingIndex) { bufferReadingIndex++; if(bufferReadingIndex>=size){ bufferWritingIndex=0; } rxByte = rxBuff[bufferReadingIndex]; pc.putc(rxByte); // Output } }
I've tried to change the RxInterrupt and the readpc but it doesnt work.
Ive got a solution:
Uart communication
event.call_every(3500, callback(clearBuff)); void clearBuff() { memset(rxBuff,0,size);//reset RXbuffer bufferWritingIndex = 0; bufferReadingIndex = 0; }