Upgrading Firmware

Details on upgrading firmware.

We will be supplying a simple JTAG programmer that will allow everyone who purchased a PTHAT to upgrade new any new version of the firmware that gets released.

It will also allow other developers who would like more control over the hardware to program their own code for the ARM STM32F411 processor that is used on the PTHAT.
We cover development further on down this page.

Please note although the PTHAT is crammed with commands and features, it is still and will always be under development as we get feed back and fix any bugs or add features requests as required. For this reason we have provided an easy way to upgrade new releases of the firmware by supplying each mainboard with a Jtag programmer.

How to upgrade the firmware.

Programming the PTHAT with the latest firmware is very simple.

1.) The PTHAT can be upgraded without it connected to the Raspberry Pi. Connect the ribbon cable as shown in the picture.

2.) Download and install the STM32 Link Utility software using this link.

You can upgrade the firmware with the PTHAT not connected to anything, or if it is already attached to the Rapsberry Pi, then it is not an issue to also upgrade. The Jtag will supply the power needed when upgrading.

Make sure you connect the ribbon cable as shown in the pictures, if you get it the wrong way around, then you may damage your board.

After you have downloaded and installed the ST Link Utility software, simply launch it using the Icon that the install program created.

1.) Click the Open file Icon, top left of the screen.

2.) Browse to the latest PTHAT firmware file, select it and click the Open button.

1.) Click on the Program Verify Icon which should then open up the download window.

2.) Click on the Start button to start it programming.

After programming is complete, it will confirm this with a message in the debug window.

Next just disconnect the ribbon cable and you are ready to use the PTHAT again.

Developing Firmware for the PTHAT

Details on Firmware development.

We fully appreciate that some advanced users of the PTHAT will want to develop their own firmware and we have no problems with this and fully encourage it.
Feel free to send us your firmware and we will publish it here for other users to download and try out.

To help you develop firmware we are going to list all the details of PCB from clock settings to GPIO connections to help you along. You can also check out the Overview page at the bottom that highlights each component on the PTHAT boards.

Below is a high level overview of main Peripherals we use on the processor and the main external components.


Processor and Clock settings.

The processor we use on the PTHAT is the ARM STM32F411RE.

The clock settings can get complicated but the main thing is we need to make sure our attached peripherals are clocked at the correct speed.

Find below a picture of the Clock Configuration.

We use the Internal Oscillator of the ARM processor which is 16Mhz but with the help of the Phase Locked Loop (PLL) we can get the System clock up to 100MHz and then divide down where needed for our peripherals.

On the PTHAT we use the following:

SPI1 X-Axis DDS Generator APB2
SPI4 Y-Axis DDS Generator APB2
SPI3 Z-Axis DDS Generator APB1
SPI5 E-Axis DDS Generator APB2

USART2 Serial Communications APB1
I2C1 Alternative Communication APB1

Timer2 for counting pulses back on X-Axis APB1
Timer5 for counting pulses back on Y-Axis APB1
Timer3 for counting pulses back on Z-Axis APB1
Timer4 for counting pulses back on E-Axis APB1

As you can see it is important that we get the Clock correct on APB1 and APB2 buses.

So the main settings should be:

HSI oscillator set to speed of 100MHz
Main PLL = On
PLLM = 16
PLLN = 400
PLLP = 4
HSI Clock Selected as PLL
PLLQ = 9
PLL selected as Main system clock
SYSCLK AHB divided by 1
APB1 = Divide by 2
APB2 = Divide by 2

GPIO port settings.

The We use nearly all the pins/ports of the processor and here is a list of them and how they should be set. You do not have to worry about pull ups as we have added pull up resistors on the PCB.


X-Axis DDS FSYNC line PB2 set as Output
Y-Axis DDS FSYNC line PC3 set as Output
Z-Axis DDS FSYNC line PC5 set as Output
E-Axis DDS FSYNC line PC4 set as Output
X,Y,Z,E Axis Stepper Enable line PC12 set as Output
X-Axis Direction line PC8 set as Output
Y-Axis Direction line PC9 set as Output
Z-Axis Direction line PC10 set as Output
E-Axis Direction line PC11 set as Output
Switches AUX1 On/Off PC0 set as Output
Switches AUX2 On/Off PC1 set as Output
Switches AUX3 On/Off PD2 set as Output
X-Axis Pulse Enable switch PB12 set as Output
Y-Axis Pulse Enable switch PB10 set as Output
Z-Axis Pulse Enable switch PB14 set as Output
E-Axis Pulse Enable switch PB15 set as Output
SPI1 SCLK>X DDS-SCLK PA5 set as Output
SPI1 MOSI>X DDS-SDATA PA7 set as Output
SPI4 SCLK>Y DDS-SCLK PB13 set as Output
SPI4 MOSI>Y DDS-SDATA PA1 set as Output
SPI3 SCLK>Z DDS-SCLK PB3 set as Output
SPI3 MOSI>Z DDS-SDATA PB5 set as Output
SPI5 SCLK>E DDS-SCLK PB0 set as Output
SPI5 MOSI>E DDS-SDATA PA10 set as Output
USART2 Transmit line PA2 set as Output push-pull


X-Axis Limit Switch PC7 set as Input
Y-Axis Limit Switch PA8 set as Input
Z-Axis Limit Switch PA9 set as Input
E-Axis Limit Switch PC13 set as Input
Emergency Stop PB7 set as Input
Choose Serial High Speed or Low Speed on Jumper PC2 set as Input
Timer2 Count PA15 set as Input
Timer5 Count PA0 set as Input
Timer3 Count PC6 set as input
Timer4 Count PB6 set as Input
ADC Channel9 PB1 set as Input
ADC Channel4 PA4 set as Input
USART2 Receive line PA3 set as Input

GPIO Alternate functions.

A lot of the Pins on the ARM processors can be used for more than one role and these are known as Alternate functions (AF0-AF15. for example a pin could be used for a Timer input but also as a Data line for SPI.

Here is a break down of ports that need to be mapped as Alternate functions.

SPI1 X-Axis DDS Pulse Generator communication

SPI4 Y-Axis DDS Pulse Generator communication 

SPI3 Z-Axis DDS Pulse Generator communication

SPI5 E-Axis DDS Pulse Generator communication

Notice on SPI4 that two ports are AF06 and one is AF05, so be careful as not all ports for the same peripheral are always on the same AF.

USART2 Serial communications

Timer2 Ch1 for counting pulses back on X-Axis

Timer5 Ch1 for counting pulses back on Y-Axis

Timer3 Ch1 for counting pulses back on Z-Axis

Timer4 Ch1 for counting pulses back on E-Axis

Alternate Functions are selected through GPIOx_AFR registers.

Lets take as an example, the SPI5 E-Axis DDS Pulse Generator

The GPIOx_AFRL Low Register sets ports 0-7, we know that we need to set PB0 to AF06
So GPIOB_AFRL is the register we are going to set and AFRL0 as shown below

The GPIOx_AFRH Higher Register sets ports 8-15, we know that we need to set PA12 and PA10 to AF06
So GPIOA_AFRL is the register we are going to set with AFRL10 and AFRL12 as shown below

Also there is the GPIO port mode register (GPIOx_MODER) which sets the ports to Alternate function mode.
Again this has to be set for each port, So for PB0, GPIOB_MODER is the register we are going to set with MODER0 as shown below:

For PA10 and PA12, GPIOA_MODER is the register we are going to set with MODER10 and MODER12 as shown below.

Note for the ADC ports Channel9 PB1 and Channel4 PA4 we need to set the MODER to 11 Analog mode.

As you can see, there is a fair bit of work to do when setting a lot of ports as Alternate Functions, but it has to be done!

Processor Peripherals.

The main Peripherals we use on the processor are the USART, Timers and SPI’s.
We shall cover each one next.

If you have not done so far, then we highly recommend that you download the RM0383 Reference manual for the STM32F411 processor from the following link:

There are many different compilers out there and most will have commands to setup the peripherals for you, but if you have to set at register level then the details below should help.


We use the timers as simple counters and use one for each Axis.

Timer2 (32 bit) Channel 1 for counting pulses back on X-Axis
Timer5 (32 bit) Channel 1 for counting pulses back on Y-Axis
Timer3 (16 bit) Channel 1 for counting pulses back on Z-Axis
Timer4 (16 bit) Channel 1 for counting pulses back on E-Axis

16 bit timers allow a max of ‭65535‬ pulses to be counted and 32 bit timers allow for ‭4294967295‬ pulses to be counted.
Now ‭4294967295‬ pulses is acceptable as even with a high resolution setup like 1000 pulses per mm travel, it will allow 4294967mm (4294 Meters, 2.6 miles) of travel before rolling over from 1 command. But 16 bit counter in a high resolution setup would only allow 65mm travel in one command.
But not to worry we simply use an interrupt for timer3 and timer4 so when they do roll over we store the multiplier in a variable.

With each timer we setup in the following order:

  • Enable bus clock for each timer RCC APB1 peripheral clock enable register (RCC_APB1ENR) TIM2EN=1 TIM5EN=1 TIM3EN=1 TIM4EN=1
  • Disable each timer by setting the TIMx control register 1 (TIMx_CR1) and set the CEN bit to 0
  • Set each Timer Prescaler to 0 TIMx prescaler (TIMx_PSC)
  • Set Timer2 and Timer5 to 4294967295 pulses and Timer3 and Timer4 to ‭65535 in the TIMx auto-reload register (TIMx_ARR)
  • Set the Slave mode selection bits (SMS) to 111 External Clock Mode in each TIMx slave mode control register (TIMx_SMCR)
  • Set the Trigger selection (TS) to 101 Filtered Timer Input 1 (TI1FP1) in each TIMx slave mode control register (TIMx_SMCR)
  • Set the Input polarity to 00 noninverted/rising edge (CC1NP/CC1P) in each TIMx capture/compare enable register (TIMx_CCER)
  • For Timer3 and Timer4 set up the Interrupt Enable 1 (UIE) TIMx DMA/Interrupt enable register (TIMx_DIER)

You will need to set TIMx control register 1 (TIMx_CR1) and set the CEN bit to 1 to enable the timers and also set up your Interrupt routines for Timer3 and Timer4.

That is your timers setup as counters and to monitor the pulse count on each timer just read out the TIMx counter (TIMx_CNT) register.

Serial Peripheral Interface bus (SPI):

We use 4 of the SPI’s to communicate with the DDS Pulse Generators

SPI1 communicates with the X-Axis DDS Pulse Generator
SPI4 communicates with the Y-Axis DDS Pulse Generator
SPI3 communicates with the Z-Axis DDS Pulse Generator
SPI5 communicates with the E-Axis DDS Pulse Generator

We only use the SPI’s to send data out and not receive in.

With each SPI we setup in the following order:

  • Enable bus clock for each SPI RCC APB1 peripheral clock enable register (RCC_APB1ENR) SPI3EN=1
  • Enable bus clock RCC APB2 peripheral clock enable register (RCC_APB2ENR) SPI1EN=1 SPI4EN=1 SPI5EN=1
  • Disable each SPI by setting the SPI control register 1 (SPI_CR1) and set the SPE bit to 0
  • Set Speed to Clock/2 000 in SPI control register 1 (SPI_CR1) and set BR to 000
  • Set to Master mode in SPI control register 1 (SPI_CR1) and set MSTR to 1
  • Data Frame Format is 16-bit data size in SPI control register 1 (SPI_CR1) and set DFF to 1
  • Clock Polarity IDLE state is Hi, ACTIVE state is Lo in SPI control register 1 (SPI_CR1) and set CPOL to 1
  • Clock Phase Data is sampled on the first clock edge transition in SPI control register 1 (SPI_CR1) and set CPHA to 0
  • Bit Sending Hierarchy Most Significant Bit (MSB) sent first in SPI control register 1 (SPI_CR1) and set LSBFIRST to 0
  • Software Slave Management disable in SPI control register 1 (SPI_CR1) and set SSM to 0

You will need to enable each SPI by setting the SPI control register 1 (SPI_CR1) and set the SPE bit to 1

USART2 Serial Port:

Using the serial port for sending and receiving data is the easiest method of communication, even though we have also linked the I2C lines out to the Raspberry PI. But for the moment we will assume everyone is happy using the serial port.

In our firmware we decided on two speeds, 115200 baud and 460800 baud that is selectable by the end user using a jumper on board. We can actually push the serial port much higher than this, but wanted a stable middle ground and decided for our firmware to have a top speed of 460800 baud. But it is up to you if you want to push it higher. In tests we communicated upto speeds of 921600 baud with no issues.

We left in the 115200 baud option for people wanting to interface the PTHAT to other MCU’s or interfaces that do not support speeds of over 115200 baud.

The default settings for the USART2 give you no hardware flow control, 8 data bits, no parity and one stop bit, so no need to set these registers. But if you did want to set them then check out the manual. 

You will need to set the USART in the following order:

  • Enable bus clock for USART2 RCC APB1 peripheral clock enable register (RCC_APB1ENR) USART2EN=1
  • Set Baud rate register (USART2_BRR) USART2_BRR = Fck/BAUDRATE
  • Enable Transmit in the Control register 1 (USART2_CR1) TE=1
  • Enable Receive in the Control register 1 (USART2_CR1) RE=1
  • Enable USART2 in the Control register 1 (USART2_CR1) UE=1


Programming each DDS Pulse Generator.

Have a dedicated pulse generator for each Axis means that you can simply set a pulse train going by programming it with the frequency you want the pulses to run at.

We are clocking the DDS chips with a 1MHz crystal which will give us 0.004Hz resolution.

The pins for each SPI and other pins have been described above already and here is the control sequence to set DDS X-Axis frequency.

First we have to calculate our frequency and store it in a variable that for this example we have named Xfrequency.
Say we wanted to set the frequency to 25100.004 Hz
As we are using a 1MHz clock for the DDS we can use the following calculation
25100.004*268.435456 = 6737731

Two write operations are required to load a complete word into either of the frequency registers.
The first write contains the 14 LSBs of the frequency word, and the next write contains the 14 MSBs. The first two bits of each 16-bit word define the frequency register to which the word is loaded and should, therefore, be the same for both of the consecutive writes.
So if we take 6737731 from our calculation and store it in our variable Xfrequency and then break it down into 28 bits. From the right take the first 14 bits and that is our XfrequencyLSB, we then add the register we want to load it into and specify this 01 on bits 16 and 15 (This is the 0x4000 in sending routine below). Then we do the same from the remaining half of bits left and store these in XfrequencyMSB and again add on 01.

‘Send a Reset.
Take X-Axis DDS FSYNC line LOW
Wait for 1us
SPI1 Write(0x2100)
Take X-Axis DDS FSYNC line HIGH

‘Write out 16 bits lower (LSB)
Take X-Axis DDS FSYNC line LOW
Wait for 1us
SPI1 Write(0x4000 + XfrequencyLSB)
Take X-Axis DDS FSYNC line HIGH
‘Write out 16 bits higher (MSB)
Take X-Axis DDS FSYNC line LOW
Wait for 1us
SPI1 Write(0x4000 + XfrequencyMSB)
Take X-Axis DDS FSYNC line HIGH
‘Write out 0xC000 16 bits for phase
Take X-Axis DDS FSYNC line LOW
Wait for 1us
SPI1 Write(0xC000)
Take X-Axis DDS FSYNC line HIGH

‘write 0x2028 for square wave and release reset
Take X-Axis DDS FSYNC line LOW
Wait for 1us
SPI1 Write(0x2028)
Take X-Axis DDS FSYNC line HIGH

This will now start the DDS sending out the pulse train at the set frequency, but we still have to allow that pulse train out by taking the X-Axis Pulse Enable switch HIGH.
The reason we have the Pulse Enable switches for each Axis is so when the pulse count has completed, we can immediately stop the pulse train and only allow the exact number of pulses to be sent out. 

Hopefully that is enough information ! .

Above we should of covered enough to get you started in developing your own firmware for the PTHAT, but if you have any questions not covered in the information then please feel free to ask in the forums on this site.

We are not in the position to teach you how to write code and there are loads of sites and forums out there already to assist you in learning, but we will do our best to help out when it comes to details of specific items relating the PTHAT.


Share This