Silicon Labs Silicon Labs Community
silabs.com
Language
  • 简体中文
  • 日本語
  • MCUs
    • 8-bit MCU
    • 32-bit MCU
  • Wireless
    • Bluetooth
    • Proprietary
    • Wi-Fi
    • Zigbee & Thread
    • Z-Wave
  • More Products
    • Interface
    • Isolation
    • Power
    • Sensors
    • Timing
  • Development Tools
    • Simplicity Studio
    • Third Party Tools
    • Thunderboard
  • Expert's Corner
    • Announcements
    • Blog
    • General Interest
    • Projects
  1. Community - Silicon Labs
  2. Blog

Chapter 8.3: Communicating Asynchronously: USART Interrupts, Clocking and Electrical Signaling

12/344/2015 | 06:19 AM
lynchtron

Level 5


makers-iot_-_background_8.3.png

 

In the last section, we configured the USART0 for serial data transfer through the use of the configurator tool.  In this section, we will write some software that springs into action whenever a data arrives at USART0 from an external device.  We will also examine the waveforms seen on the serial bus with an oscilloscope, so that you know what to look for if you don’t see anything on your board.  We will wrap up this section with a look at how to calculate the USART clock frequencies that are reachable with the clock modules current configuration.

 

USART0 Interrupts

Now that I have initialized the USART0 instance of the USART peripheral, I will enable interrupts and set up an interrupt handler to do something when new data arrives. 

 

#include "em_device.h"
#include "em_chip.h"
#include "InitDevice.h"
#include "em_usart.h"
 
/**************************************************************************//**
 * @brief  Main function
 *****************************************************************************/
int main(void)
{
  /* Chip errata */
  CHIP_Init();
 
  enter_DefaultMode_from_RESET();
 
  USART_IntClear(USART0, USART_IF_RXDATAV);
  USART_IntEnable(USART0, USART_IF_RXDATAV);
 
  NVIC_ClearPendingIRQ(USART0_RX_IRQn);
  NVIC_EnableIRQ(USART0_RX_IRQn);
 
  /* Infinite loop */
  while (1) {
  }
}
 
void USART0_RX_IRQHandler(void)
{
      if (USART0->IF & USART_IF_RXDATAV)
      {
            char test_char = USART_Rx(USART0);
      }
}

Compile and run this code, and place a breakpoint on the line that says “char test_char = USART_Rx(USART0);” in the USART0 interrupt handler.   Press the run button in Simplicity Studio, and it should NOT hit the breakpoint because there should be no data arriving at the USART RX buffers yet.

Connect your PC0 pin (USART TX) on the Starter Kit to the RXD pin on the CP2104 MINIEK board.  Connect PC1 pin (USART RX) to the TXD pin on the CP2104.  Also connect the GND pin on the Starter Kit to a ground pin on the CP2104.  DO NOT connect any of the VDD pins, as each board gets power from their own USB cable in this configuration..  The only time that you will connect the VDD of the CP2104 device to a target device is when you intend to power that device over USB.  That can be done, but it is not how we are currently using the Starter Kit.  Plug in the CP2104 MINIEK board to your computer if you haven’t done that already and fire up your terminal emulator using the settings described previously.

8.3_conns.jpg
  

You should then be able to type a character on the terminal emulator on your computer and see the breakpoint event happen in Simplicity Studio.  Single step once and then examine the value of the data within the test_char variable.  When you hover on the variable, Simplicity Studio shows you the content of the variable using a pop-up window in a binary format as well as an ASCII text format in quotes.  The ASCII value should match the character that you typed in the terminal.

 

If you did not see a breakpoint occur when you typed in your terminal emulator, make sure that you have set the correct serial port in your terminal emulator, and that the baud and other parameters are set correctly.  If you have unplugged and reconnected your USB-to-serial port adapter, you will need to restart your terminal emulator or refresh the available COM ports and try again.    Also, double check your connections between the serial port adapter’s TX/RX pins to PC0 and PC1.  Note that the silkscreen for PC2 is located above the pin unlike all the other pin labels, which may make it appear that PC1 is the last pin in the row, but it is actually the second-to-last pin in the header strip.

 

Press the resume button and note that the interrupt does not happen again until you press another key on the keyboard.  The USART RXDATAV interrupt flag is cleared automatically.  Some interrupt flags in EFM32 are cleared automatically and some require a manual clear; you just have to read the Reference Manual when you are unsure.

 

Now remove the breakpoint and press the resume button in Simplicity Studio.  Type more keys on the keyboard and you will notice that nothing at all happens.  Inside the MCU, there are surely interrupts happening and running, but it is a poor user experience.  Therefore, let’s add some commands to echo the data back from the MCU to the terminal emulator.  Add this line inside the USART0 interrupt handler just after the “char test_char = USART_Rx(USART0);” line:

 

USART_Tx(USART0, test_char);

Disconnect from your debug session in Simplicity Studio and rebuild, then re-launch the debug session.  You should now be able to see what you type show up on the terminal emulator screen.  Congratulations, you just created a bidirectional communication link to your MCU!  And the nice part about this is that if you see text show up in your terminal, you know that the MCU is alive and working.  If there is no text when you type, then it tells you that your MCU is either locked up or powered off. 

 

Electrical Waveforms

Hopefully you have been able to follow along and see evidence that everything is working.  But what if it is not working?  You can only double-check your com port so many times, right?  Or what if some of your characters are garbled?  At some point, you will need to break out an oscilloscope to see what is happening down at the physical interface level. 


I have attached my oscilloscope to the header pins underneath the jumpers and captured the following waveform when I typed the letter j on the keyboard.  The blue channel is on the signal that is transmitting from the computer to the MCU, and the red channel is on signal that is transmitting from the MCU to the computer.  You can see that the two data packets match and that they are separated by around 20 microseconds, which is the time that it takes for the interrupt handler to leap into action and spit the received data back out on the line to the computer. 

8.3_wide_waveform.png
  8.3_probes.jpg

The RS-232 standard transmits 10 bits per packet, and in this case the packet is the letter j.  The first bit is always a zero, which is the start bit.  The last bit is the stop bit, which is 1.  The eight bits in between are the ASCII code for the letter j, which is 0x6A or 0b01101010.  This is sent backwards from how we write it, so bit zero is sent first, ending with bit seven.  I don’t know why the designers didn’t send the most significant bit first, so it would match how we write it, or why people drive on the left side of the road in some countries.  It’s just the way it is.  You will run into this bit-ordering problem (or endianness) often in embedded development.

8.3_detail_waveform.png

 

Clock Sources for Asynchronous Communication

The Silicon Labs application note “AN0045 USART/UART – Asynchronous mode” states that crystals should be used for asynchronous communication instead of the RC clock sources.  This is because the decoding of asynchronous signals requires a clock recovery mechanism. 

 

When data is transmitted without a clock signal, the receiver must create a clock to sample the data packet all on its own.  Both the transmitter and receiver have been configured with the same clock rate, but neither side knows exactly when to sample each data bit.  The only thing that the receiver gets is a start bit, and that can happen at any moment in time.  After that, the receiver has to sample multiple bit times and then find the stop bit.  Accurate positioning of these clock edges after the start bit requires an accurate clock, and the HFRCO is not always as accurate as necessary to ensure trouble-free operation.  It can be achieved if tuning and temperature compensation is performed on the HFRCO clock source, but it is easier to use a crystal-based clock source.

 

By using the HFXO (remember, X stands for crystal) as the clock source for the HF clock, the app note states that a range of baud rates between 244 and 8M baud can be reached if the HF clock is running at 32MHz.  Things change as your HF divider changes, so you will need to reinitialize the USART at every core clock divider change and ensure that the baud rate you want is reachable.

 

There are some functions in the USART API to help you figure out if the clock frequency that you want to use is reachable.  The first is USART_BaudrateCalc which simply performs math on the given reference clock frequency, clock divisor (between 1 and 32767), the syncmode (false for asynchronous), and the over sampling factor, which is 16 by default but can be set to 4, 6, 8, or 16.

uint32_t USART_BaudrateCalc(uint32_t refFreq,
                            uint32_t clkdiv,
                            bool syncmode,
                            USART_OVS_TypeDef ovs)

 

The function USART_BaudrateAsyncSet will attempt to configure the proper clock divisor with a given USART instance, reference frequency, the desired baud rate, and oversampling factor.

 

void USART_BaudrateAsyncSet(USART_TypeDef *usart,
                            uint32_t refFreq,
                            uint32_t baudrate,
                            USART_OVS_TypeDef ovs)

 

The only way to know if the set was successful is to call on the function USART_BaudrateGet and compare that to your desired baud rate that you sent into the USART_BaudrateAsyncSet function.  Note that your baud rates will usually be a little bit off as described in the Reference Manual.

 

uint32_t USART_BaudrateGet(USART_TypeDef *usart)

 The USART_BaudrateAsyncSet and USART_BaudrateGet functions should be called after the CMU and USART have been initialized as desired, or after a HF clock divisor change.  The USART_BaudrateCalc function can be called at any time because it only performs some math calculations and doesn’t actually set anything in the hardware.

 

In the next lesson, we will put the serial interface to work as a debug print generator.

 

PREVIOUS | NEXT

 

  • Blog Posts
  • Makers
  • neerajdorle

    Level 3


    Replied Jan 05 2017, 12:15 PM

    Hi, 

     

    I have followed all the steps given in the tutorial(chapters 8.2 and 8.3). But I am getting an error while I am trying to build the application;

     

    "C:\Users\gs-1148\SimplicityStudio\v4_workspace\emptyCxxProject\src\InitDevice.c",214  Error[Pe513]: a value of type "int" cannot be assigned to an entity of type "USART_PrsRxCh_TypeDef"

     

    i am using: 

    Gecko SDK 5.0

    Device: EFR32MG1P232F256GM48

    0

Tags

  • Wireless
  • High Performance Jitter Attenuators
  • EFR32MG21 Series 2 SoCs
  • Blue Gecko Series 2
  • Zigbee SDK
  • ZigBee and Thread
  • Internet Infrastructure
  • Sensors
  • Blue Gecko Bluetooth Low Energy SoCs
  • Z-Wave
  • Micrium OS
  • Blog Posts
  • Low Jitter Clock Generators
  • Bluetooth Classic
  • Makers
  • Flex SDK
  • Tips and Tricks
  • Smart Homes
  • IoT Heroes
  • Reviews
  • RAIL
  • Simplicity Studio
  • Mighty Gecko SoCs
  • Timing
  • Blue Gecko Bluetooth Low Energy Modules
  • Clocks
  • Ultra Low Jitter Clock Generators
  • General Purpose Clock Generators
  • Industry 4.0
  • Giant Gecko
  • 32-bit MCUs
  • blue-gecko-xpress-modules
  • Bluetooth Low Energy
  • 32-bit MCU SDK
  • Gecko
  • Microcontrollers
  • News and Events
  • Industrial Automation
  • Wi-Fi
  • Bluetooth SDK
  • Community Spotlight
  • Biometric Sensors
  • General Purpose Jitter Attenuators
  • Giant Gecko S1
  • Flex Gecko
  • Internet of Things
  • 8-bit MCUs
  • Isolation
  • Powered Devices

Top Authors

  • Avatar image Mark Mulrooney
  • Avatar image Siliconlabs
  • Avatar image Nari Shin
  • Avatar image lynchtron
  • Avatar image deirdrewalsh
  • Avatar image Lance Looper
  • Avatar image lethawicker

Archives

  • 2014 December
  • 2015 January
  • 2015 February
  • 2015 March
  • 2015 April
  • 2015 May
  • 2015 June
  • 2015 July
  • 2015 August
  • 2015 September
  • 2015 October
  • 2015 November
  • 2015 December
  • 2016 January
  • 2016 February
  • 2016 March
  • 2016 April
  • 2016 May
  • 2016 June
  • 2016 July
  • 2016 August
  • 2016 September
  • 2016 October
  • 2016 November
  • 2016 December
  • 2017 January
  • 2017 February
  • 2017 March
  • 2017 April
  • 2017 May
  • 2017 June
  • 2017 July
  • 2017 August
  • 2017 September
  • 2017 October
  • 2017 November
  • 2017 December
  • 2018 January
  • 2018 February
  • 2018 March
  • 2018 April
  • 2018 May
  • 2018 June
  • 2018 July
  • 2018 August
  • 2018 September
  • 2018 October
  • 2018 November
  • 2018 December
  • 2019 January
  • 2019 February
  • 2019 March
  • 2019 April
  • 2019 May
  • 2019 June
  • 2019 July
  • 2019 August
  • 2019 September
  • 2019 October
  • 2019 November
Silicon Labs
  • About Us
  • In the News
  • Email Newsletter
  • Cookies
  • Contact Us
  • Community
  • Site Feedback
  • Investor Relations
  • Blog
  • Privacy and Terms
  • Corporate Citizenship
Copyright © Silicon Laboratories. All rights reserved.
粤ICP备15107361号-1