7 months, 3 weeks 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?

Comment on this question

1 Answer

7 months, 3 weeks 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;
}   

posted by Ireno Wälte 28 Jan 2019