Understanding the Clock Subsytem
As mentioned, the vendor provides a repo of examples for their various chips. You can study them to use the various peripherals. So we won't repeat them here. But we'll discuss one crucial component - the clock.
One peculiarity of these Si-Labs chips (at-least the efr32Xg21 family) is they take a fixed 38.4MHz crystal for the external source. This simplifies a lot of the clock setup configs.
Here is a basic diagram with the most used components.
Note that the chip boots on FSRCO
then switches to HFRCODPLL
before executing user firmware.
Setting up for external crystal#
Our ZYZBP008
module comes with an external crystal attached (according to the datasheet, it is mandatory to source from the external clock to enable the radio unit). Here is a code excerpt from the example repo on how to configure for the external source:
#include "em_cmu.h"
#include "em_chip.h"
int main(void)
{
CHIP_Init();
// Start the HFXO with safe default parameters
CMU_HFXOInit_TypeDef hfxoInit = CMU_HFXOINIT_DEFAULT;
CMU_HFXOInit(&hfxoInit);
CMU_OscillatorEnable(cmuOsc_HFXO, true, true);
// enable^ ^wait until clock succeeds before returning
// Switch the SYSCLK to the HFXO.
CMU_ClockSelectSet(cmuClock_SYSCLK, cmuSelect_HFXO);
while(1);
return 0;
}
Lookup for these functions and their possible options in the clock component documentation. CMU_HFXOINIT_DEFAULT
is defined in em_cmu.h
and apparently suitable in most usual cases.
To verify that it works, we will test the UART peripheral (which is time sensitive).
#include "em_cmu.h"
#include "em_chip.h"
#include "em_gpio.h"
#include "em_usart.h"
#define BSP_BCC_TXPORT gpioPortA // A05 - TX
#define BSP_BCC_TXPIN 5 //
#define BSP_BCC_RXPORT gpioPortA // A06 - RX
#define BSP_BCC_RXPIN 6 //
int main (void)
{
CHIP_Init();
// Start the HFXO with safe default parameters
CMU_HFXOInit_TypeDef hfxoInit = CMU_HFXOINIT_DEFAULT;
CMU_HFXOInit(&hfxoInit);
CMU_OscillatorEnable(cmuOsc_HFXO, true, true);
// Switch the SYSCLK to the HFXO.
CMU_ClockSelectSet(cmuClock_SYSCLK, cmuSelect_HFXO);
CMU_ClockEnable(cmuClock_GPIO, true);
GPIO_PinModeSet(gpioPortA, 0/*pin 4*/, gpioModePushPull /*push-pull output*/, 1/*output level*/);
CMU_ClockEnable(cmuClock_USART0, true);
USART_InitAsync_TypeDef initAsync = USART_INITASYNC_DEFAULT;
initAsync.baudrate = 115200;
GPIO->USARTROUTE[0].TXROUTE = (BSP_BCC_TXPORT << _GPIO_USART_TXROUTE_PORT_SHIFT)
| (BSP_BCC_TXPIN << _GPIO_USART_TXROUTE_PIN_SHIFT);
GPIO->USARTROUTE[0].RXROUTE = (BSP_BCC_RXPORT << _GPIO_USART_RXROUTE_PORT_SHIFT)
| (BSP_BCC_RXPIN << _GPIO_USART_RXROUTE_PIN_SHIFT);
GPIO->USARTROUTE[0].ROUTEEN = GPIO_USART_ROUTEEN_RXPEN | GPIO_USART_ROUTEEN_TXPEN;
USART_InitAsync(USART0, &initAsync);
GPIO_PinModeSet(BSP_BCC_TXPORT, BSP_BCC_TXPIN, gpioModePushPull, 1);
GPIO_PinModeSet(BSP_BCC_RXPORT, BSP_BCC_RXPIN, gpioModeInput, 0);
//USART_Tx (USART_TypeDef * usart, uint8_t data)
char buf[] = "Hello";
while(1) {
GPIO_PinOutToggle(gpioPortA, 0/*pin 4*/);
for (int i = 0; i < 6; i++) {
USART_Tx (USART0, buf[i]);
USART_Tx (USART0, '\n');
}
for (volatile uint32_t i = 0; i < 100000; i++) { } // busy delay
}
return 0;
}
The above code should print Hello via serial repeatedly with the roughly specified pauses.