An FPGA And Embedded Engineering Blog

Category: MCU

nrf5340-DK vs nrf52-DK

The nrf5340-DK from Nordic Semiconductors just arrived in the mail. Let’s have a look at what sets it apart from the nrf52-DK featuring an nrf52832!

Picture of a breadboard, an nrf52-DK on the left and an nrf5340-DK on the right. Saleae Logic Analyzer trying to steal itself into the picture.
nrf52-DK on the left, nrf53-DK on the right. Saleae Logic Analyzer trying to steal itself into the picture.

The Dev-Board

The differences

Looking at the two boards side-by-side, the first thing we notice is the bigger size of the dev-board. This is probably mostly due to the increased number of GPIO pins the nrf5340 supports. It features twice as many I/O pins as the nrf52832 (2 ports of 32 pins instead of just 1).

The nrf53-DK also comes with the possibility to run it on a Li-po battery and the power source can be chosen accordingly with a switch. In addition, the nrf53-DK also has a USB connector that is directly interfaced to the target MCU. The ESD protection circuit features a PRTR5V0U2X, which looks interesting and will probably be on the BOM of my next PCB featuring an USB connector, but I digress…

The commonalities

For the rest, the two boards have a lot in common, they feature an NFC connector as well as a PCB antenna and SMA connectors for adding an external antenna. Both have debug headers that can be used to program and debug external devices, and they also both have current measurement support, which comes in handy if we need to do current profiling of applications.

The nrf5340-DK actually features two nrf5340s! Here, the first one (U1) is the one that’s actually connected to all the peripherals, on the DK. The second one (U2) is only used for programming and debugging (U2). Nordic calls this second MCU the interface MCU .This is similar to the nrf52-DK, however the older revision of the nrf52-DK I am using still features a Microchip ARM-MCU (ATSAM3U2CA) as an interface MCU, while on newer revisions you’d also find an nrf5340.

As usual, the board comes in an Arduino compatible design. Arduino shields are easily applied and used for prototyping. LEDs and Buttons can be found on both, even though they aren’t interfaced to the same pins.

The Documentation

I have to say, when it comes to documentation, Nordic is on top of the game. They provide a lots of detail while not overloading you with information. A single ZIP-File containing all the production files is available for download, including gerber files. Even pick-and-place files are in there so these development boards are essentially open source hardware! There is also a pdf schematic in the ZIP-file and we find everything with a simple Google-Search. (Here for the nrf52-DK and here for the nrf53-DK) That’s top of the line and I can’t see a big difference between the nrf52-DK and the nrf53-DK. Keep that up Nordic!

The Processor

Now for the heart and brain of the boards, the processors. The nrf5340 is quite a lot beefier than the nrf52832.


Instead of a single processor, the nrf5340 features two Arm® Cortex®-M33 processors, where one is marketed as the “Application core” and one as the “Network core”. The application core comes with a lot of debug-ability supporting different Trace-interfaces. It also contains a Arm TrustZone CryptoCell™-312 security subsystem that allows for hardware accelerated computation of common cryptographic algorithms and PRNG.


While the nrf52832 only has measly 512kB flash and 64kB of RAM, the nrf5340 has 1MB of flash memory and 512(!)kB of RAM – now that’s an improvement.


In terms of peripherals, there isn’t too much of a difference between the two, as both feature the common usual suspects – SPI, I²C, I²S and UART. The nrf5340 has the already mentioned USB-support and also supports QSPI. Everything can be interfaced using the programmable peripheral interconnect so we aren’t forced to use certain pins for certain functions.

Wireless communication

Finally, in addition to the nrf52’s BLE, BL Mesh and ANT™ support, the nrf5340 also supports IEEE 802.15.4, which makes it ready for Matter, Thread and Zigbee, so it is even more applicable for the IoT devices of the coming decade.


The nrf52-DK and nrf53-DK have commonalities and differences. Both devices have their place and knowing the differences is key in knowing when to use which device. In general, these devices are quality products and if you can get away with an nrf52832, it should definitely be used. Having both to my disposal enables me to quickly evaluate solutions and find the most appropriate device for the task.

Generating sine-waves using PWM – Sine pulse width modulation with an STM32 Cortex M0 device

Often times, harmonic signals, such as sinewaves are needed. However, many microcontrollers do not feature a digital to analog converter (DAC) and therefore lack the ability to output analog voltages directly. However, practically every microcontroller comes with a pulse width modulation (PWM) output, or at least have a hardware timer which can be programmed to create a PWM signal. The idea behind sine pulse width modulation (SPWM) is, that pulses are generated whose duty cycle corresponds to the amplitude of a sinewave at that point in time, with a given frequency. The PWM signal is then smoothed with a capacitor and amplified to a voltage of interest using op-amps or a simple transistor amplifier.

The idea is to have a look-up-table with a predefined number of sine-wave values. The pulse width of the next pulse is then set to the current value according to that look-up-table during the interrupt service routine. The STM32 HAL provides a callback function that can be implemented, called HAL_TIM_PWM_PulseFinishedCallback. This callback is called during an interrupt service routine. The logic for computing the next index is outsourced to another timer. This timer calls the afformentioned interrupt handler every time a period is done.

First, we have to setup the timers. For that, we will use the STM32 CubeIDE, which provides a nice visual interface to do these things. We setup timer 1, channel 1 to PWM Generation and channel 2 to Output Compare. The Prescaler is set to 1 and the Counter Period is set to PERIOD (Remember to choose “No Check” in order to be able to set a non-hex value).

The look-up-table could for example look as follows:

#define PERIOD 32 #define DC_OFFSET (PERIOD >> 1) 


The values used will be presented shortly:

– PERIOD: corresponds to the number of ticks the timer counts before it overflows. Having a lower period enables the generation of higher frequencies.

– DC_OFFSET: As we can only generate pulses with a width greater or equal to 0, we have to add half of the period as dc offset.

– PERIOD_FRACTION: A macro to compute the width of the pulse from a decimal value.

– sin[]: The actual look-up-table with the sine-function samples. The number of samples should be as low as possible in order to keep the code-size small. In addition to that, the number of samples also dictates the maximum frequency that can be generated, as every value must be held for at least one period. Finally, a small value decreases the resolution and the reconstructability of the sinusoidal shape. The table shown is the one that I settled for after a lot of trial and error. One could also obviously get away with only using a quarter period, however that would increase the computation time inside of the ISR, so a time-space-trade-off must be made.

The implemented callback functions look as follows:

void updatePWMPulse(uint16_t value) { 
    htim1.Instance->CCR1 = value; 

void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim) { 
    if(htim == &htim1 && htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2) { 
        step = (step + 1) % num_steps; 

As STM32 Timers only have a single set of these callback functions, we need to manually check if we were called by the one timer and channel of interest. Of so, we simply set the pulse for the PWM signal and increase the step.

Note, that this is channel 2, which corresponds to a simple compare timer, which triggers every time a period ends. There are a number of ways to do this, though.

In our main function, we have to start the two channels of the timer:

HAL_TIM_PWM_Start_IT(&htim1, TIM_CHANNEL_1); HAL_TIM_OC_Start_IT(&htim1, TIM_CHANNEL_2);

And that’s it for basic SPWM generation. Generating different frequencies can be done by either changing the period length, the prescaler or the number of sine-wave samples.

  1. uint16_t) ((X) * (PERIOD >> 1 []