8 years, 10 months ago.

USART Problem with NucleoF401RE

Hello;

I wanted to receive serial data from PA_10 (D0) of nucleo F401RE. To test it first, I connected arduino due TX2 pin (PIN16) to PA_10 via jumper cable.

This is the code for nucleo which receive...

#include "mbed.h"
//#include "BufferedSerial.h"


DigitalOut myled(LED1);
DigitalOut ec_pin(PB_2, 1);

Serial pc(USBTX, USBRX);
RawSerial ecs(NC, PA_10);

void interrupt();


int main()
{
    ecs.baud(1200);
    ecs.attach(&interrupt, Serial::RxIrq);


    while(1) {
    }
}

void interrupt()
{
    uint8_t Car;
    myled = !myled;
    //wait_ms(200);
    //myled = !myled;
    Car = ecs.getc();
    pc.printf("%c\r\n", Car);
    
}

... and this is the code for Arduino Due size... This is a true and working code if you dont have a knowledge of arduino due..

void setup() {
  // put your setup code here, to run once:
  //Serial.begin(9600);
  Serial2.begin(1200);
}

void loop() {
  // put your main code here, to run repeatedly:
  Serial2.print("H");
  delay(5000);
  Serial2.print("E");
  delay(5000);
  Serial2.print("L");
  delay(5000);
  Serial2.print("L");
  delay(5000);
  Serial2.print("O");
  delay(5000);

}

I can confirm that interrupt routine is working for Nucleo.. But I cant see the characters in Tera Term i.e. HELLO...

Where did I make mistake(s)? Any suggestion...Thanks...

Kamil

1 Answer

8 years, 10 months ago.

The default setup of the F401 (and other) nucleos is that D0 (PA_3, RX UART2) and D1 (PA_2, TX UART2) are not connected. The TX/RX of UART2 are the USBTX/USBRX pair used for communication with the host PC.

You will find PA_10 (RX UART1) on pin D2.

Accepted Answer

I tried PA_10 also. Connected TX2 pin of arduino due(Pin16) to D2(PA_10) of nucleo... I am sure that interrupt routine is working since led led blinking in and out every 5 secs... But there is no sign of HELLO on terminal screen of tera term...

posted by Kamil M 14 Jun 2015

Have you been able to print anything at all from the F401? Try a start pc.printf("Hello world\r\n") message in the F401 main before you enter the while (1) loop. Is the teraterm baud rate set correctly, default on mbed is 9600. Also make sure that the arduino and the F401 have a common GND pin in addition to connecting the TX from the arduino to the RX of the F401.

posted by Wim Huiskamp 14 Jun 2015

Hello Wim,

As you can see in the above code both arduino TX and Nucleo Rx baudrates are same, 1200... Tera Term is at 9600, i am sure...

I did not establish common ground pin if you mean connect both arduino and nucleo GND with jumper cable.. I will try...

Altough it is not shown in nucleo interrupt routine above, i also tried pc.printf("Interrupt\r\n") in interrupt function; and I could see it on Tera Term, which means I can enter interrupt routine ( Also led on nucleo blinking in and out every 5 secs, which corresponds to each Tx transmission from arduino (delay(5000))...)

So, the problem still exist and affecting whole my company's project, which may be lead to me to leave mbed, even I strongly regret :(

posted by Kamil M 15 Jun 2015

Ok... I solved the problem... And it is really BIG ONE...

When i set the baudrate to 1200 nucleo cant catch the characters from arduino or any other device/sensor using 1200... If it is 9600 everything is ok...

1200 baudrate is very important since all SDI-12 based sensors/devices, which only using Rx pin, are use it...

Any solution?

posted by Kamil M 16 Jun 2015

Looks like bug in mbed lib setting the baudrate. First rightclick on mbed lib in your project to make sure it is up to date. If that does not help, file a bug report on mbed source on github. You can also import the mbed lib source in your project and try to find the problem (probably in serial_api.c) Do a pull request on github when you have a solution.

posted by Wim Huiskamp 17 Jun 2015

Libraries are up to date and i looks that it is bug from mbed libs. I sent issue in github. Looking forward a solution, i hope...

posted by Kamil M 17 Jun 2015

I havent checked yet cause I dont have the hardware available at the moment, but since you do get a receive interrupt it seems that the UART as such is working but you dont get valid (printable) data. It could be that the baudrate at 1200bd deviates too much from the nominal value. Note that it is at the low end of the usual range. Have you measured the actual bitlength/baudrate transmitted on the Arduino side. Also measure it on the mbed side when it is transmitting some data on a TX pin to get an indication of the clockrate used for sampling.

posted by Wim Huiskamp 18 Jun 2015

Hello Wim,

I agree with you that, i can get interrupts, but characters are blank. I tried with %c, %s, %i, %d... No result... And i also read that 1200 baud is the min baud which nucleo can provide... But it is so disappointing that while i can read SDI-12 sensor data from the Rx pin of Arduino Due without any external crystal added, i can't get it with ST product.. So disappointing...

I did not measure the actual baudrate on the Arduino side... Moreover I have no idea how can I do it..I am not electronics guy... Sorry :( Just PhD on agriculture...

If it can be measure just only with sample code can u share?

This baudrate problem really a hard hit to project.... It is suspended on Nucleo side until a patch to this problem, if possible...

Regards...

posted by Kamil M 19 Jun 2015

Ok, so the problem is caused by the fact that 1200 baud can not be generated at the current setting of the clocksource (PCLK2 or APB2) for UART1 and UART6. That clock is running at the SystemCoreClock of 84MHz. A divider is used to reduce that to the serial port samplingrate which is 16x the baudrate (16x1200=19200). You need a divider factor of 4375 (0x1117) and that wont fit in the available 12bits in the divider register BRR. The 1200 baud is just beyond the edge of possible baudrates at 84MHz. There is no problem for 2400 baud. The code will use the truncated value of 0x117 instead and selects a wrong baudrate. This is means the UART still sees data (the Irq fires) but it can not be received correctly and is just garbled..

The easiest solution is to reduce the frequency of the UART clocksource by dividing it by 2 to 42MHz. That is already done for UART2 which connects to the host PC for printf messages.

#include "mbed.h"
#include "stm32f4xx_hal.h"

// your stuff

int main() {

  pc.baud(9600);
    
  pc.printf("Hello World !\r\n");

// Show current settings, change them and show again.
  pc.printf("CPU SystemCoreClock is %d Hz\r\n", SystemCoreClock);  
  pc.printf("PCLK1 is %d Hz\r\n", HAL_RCC_GetPCLK1Freq());    
  pc.printf("PCLK2 is %d Hz\r\n", HAL_RCC_GetPCLK2Freq());  

  pc.printf("RCC_CFGR is 0x%08X\r\n", RCC->CFGR);
  RCC->CFGR &= ~0x0000E000;  // PPRE2, Bit 15-13
  RCC->CFGR |=  0x00008000;  // PPRE2: PCLK2 = AHB / 2
  pc.printf("RCC_CFGR is 0x%08X\r\n", RCC->CFGR);  

  pc.printf("CPU SystemCoreClock is %d Hz\r\n", SystemCoreClock);  
  pc.printf("PCLK1 is %d Hz\r\n", HAL_RCC_GetPCLK1Freq());    
  pc.printf("PCLK2 is %d Hz\r\n", HAL_RCC_GetPCLK2Freq());  

  ecs.baud(1200);

// your code here
}

The core is still running at the full speed. The slower peripheral clock should not be a problem. Hopefully all of the peripherals will correctly compute their clocks from the modified APB2 clock. You may want to make sure to explicitly init all instantiated devices by calling serial.baud or i2c.frequency etc.

posted by Wim Huiskamp 20 Jun 2015

Thank you for your real support Wim... I'll try your code and share the results here...

I wonder that, What if I configure the 401Nucleo with STM32Cube and use Keil or ST Studio? Do i face with the same problem?

posted by Kamil M 20 Jun 2015

Hello,

After above configuration, i can get the characters at 1200 baud.. Thank you...

I wonder that, by configuring PCL2 clock to 42 MHz, which peripherals affected?

posted by Kamil M 23 Jun 2015

You have to check the datasheet to see which peripherals are connected to PCLK2. I think most wont be affected by a slower clock as such. You might see that the upper and lower boundaries of serial devices are defined by the clock. This is the case also for the UART. With a slower PCLK you can now get down to 1200bd, but at the same time the highest supported baudrate is now also reduced. The ARM Cortex is very flexible in clocksources, clockspeeds, peripheral speeds etc. Depending on the vendor there are some more differences. Toolsets like Cube or Keil will set default configuration values and have some wizards to help you set the appropriate configuration parameters manually and provide warnings when your values get out of range. The mbed libs have default settings, you can change them by modifying the HAL CMSIS source code.

posted by Wim Huiskamp 23 Jun 2015

This is the code for Rx... With your support thanks...

#include "mbed.h"
//#include "BufferedSerial.h"
#define bufferSize             50

int i = 0;
char Car;
bool yaz = false;
DigitalOut myled(LED1);
DigitalOut ec_pin(PB_2, 1);

Serial pc(USBTX, USBRX);
RawSerial ecs(NC, PA_10);

char buffer[bufferSize];
//char buffer2[bufferSize];
void interrupt();


int main()
{
    pc.baud(9600);

    pc.printf("Hello World !\r\n");

// Show current settings, change them and show again.
    pc.printf("CPU SystemCoreClock is %d Hz\r\n", SystemCoreClock);
    pc.printf("PCLK1 is %d Hz\r\n", HAL_RCC_GetPCLK1Freq());
    pc.printf("PCLK2 is %d Hz\r\n", HAL_RCC_GetPCLK2Freq());

    pc.printf("RCC_CFGR is 0x%08X\r\n", RCC->CFGR);
    RCC->CFGR &= ~0x0000E000;  // PPRE2, Bit 15-13
    RCC->CFGR |=  0x00008000;  // PPRE2: PCLK2 = AHB / 2
    pc.printf("RCC_CFGR is 0x%08X\r\n", RCC->CFGR);

    pc.printf("CPU SystemCoreClock is %d Hz\r\n", SystemCoreClock);
    pc.printf("PCLK1 is %d Hz\r\n", HAL_RCC_GetPCLK1Freq());
    pc.printf("PCLK2 is %d Hz\r\n", HAL_RCC_GetPCLK2Freq());

    ecs.baud(1200);
    ecs.attach(&interrupt, Serial::RxIrq);


    while(1) {

        if (yaz == true) {
            for(int j =0; j < bufferSize; j++) {

                printf("%c",buffer[j]);
            }
memset(buffer, 0, sizeof(buffer) / sizeof(buffer[0]));
yaz = false;
i=0;

            //}
        }
    }
}
void interrupt() {
    Car = ecs.getc();
    
        
        if (Car != ',')
        {
            buffer[i] = Car;
            i++;
        }
        else
        {
        yaz = true;
        }


    }

posted by Kamil M 23 Jun 2015