Skip to content

m3y54m/stm32-overclocking-challenge

Repository files navigation

STM32 Overclocking Challenge

This repository contains my solutions to a challenge on Sisoog website.

Caution

Overclocking may cause the microcontroller to overheat and result in damage. Therefore, please exercise caution and only attempt this if you know exactly what you are doing. Use the instructions in this repository at your own risk.

Challenge Statement

Write a program for the STM32F103C8T6 microcontroller to toggle the PC14 pin at the highest possible frequency.

272326556-164b9463-871c-4aa6-9023-f01f0d98a446

The program should meet the following criteria:

  • The program that achieves the highest frequency on PC14 will be considered the winner.
  • The generated signal on PC14 should maintain the same frequency for a minimum of 10 minutes.
  • It is recommended to use a Blue-Pill board as the hardware for this challenge. If required, you are allowed to replace the crystal on the board.

My Solutions

The challenge statement forces us to generate the output signal using only PC14. This is because PC14 cannot be used as the MCO, PWM, or timer outputs, so we need to find alternative methods to create a high-frequency pulse on PC14.

image

image

Solution 1

We start the process of overclocking the STM32F103C8T8 microcontroller with an external crystal of 8 MHz and setting the clock speed to 72 MHz.

image

We set the PC14 pin as a Push-Pull output without Pull-Up and connect it to the oscilloscope to see the output pulse frequency.

image

272318635-e9cd48f6-4b72-4660-af47-110bf5e82bf9

We write the program in such a way that the toggling of PC14 pin is done as quickly as possible. That's why we are using assembly instructions.

The fastest way to toggle a bit in a register is to use the XOR operation. So, before the while loop, we store the address of the GPIOC_ODR register and the mask needed to change the value of 14th bit of the PORTC in the general-purpose registers:

asm volatile(
    "ldr r0, =0x4001100C\n" // GPIOC_ODR address
    "ldr r1, [r0]\n"        // Load GPIOC_ODR value
    "ldr r2, =0x00004000\n" // Bit 14 mask
);

The address of GPIOC_ODR is adopted from the RM0008 document.

image

image

Then, inside the while loop, we first perform the XOR operation between the mask and the current value of the GPIOC_ODR register using the EOR instruction, and then write the resulting value to the GPIOC_ODR register using the STR instruction:

asm volatile(
    "eor r1, r1, r2\n" // XOR the value with the mask
    "str r1, [r0]\n"   // Store the new value back to GPIOC_ODR
);

In this way, in a short time, the PC14 pin is toggled in the while loop, and a high frequency output pulse will be obtained.

By setting SYSCLK = 72 MHz, the output pulse frequency on PC14 will have a frequency about 5.13 MHz:

272320556-3f8946e6-e471-4bcd-942c-365c4f05b9d1

Now we step by step increase the clock of the microcontroller, until it eventually reaches a point where the output signal on PC14 becomes unstable.

For SYSCLK = 80 MHz, the frequency of the output pulse on PC14 reaches approximately 5.71 MHz:

272322727-5b7ed9fc-c93c-4111-9049-84f94bee5608

For SYSCLK = 88 MHz, the frequency of PC14 reaches about 6.29 MHz:

272323179-467b4e38-9a2f-4574-8eb9-4f4194cc15c5

For SYSCLK = 96 MHz, the output pulse frequency on PC14 reaches about 6.94 MHz:

272323240-91792af6-8377-4fcd-adf8-3c8715c8dfa8

For SYSCLK = 104 MHz, the output pulse frequency on PC14 reaches about 7.46 MHz:

272323358-172efa03-de96-4679-b139-10cb421c8ed8

For SYSCLK = 112 MHz, the output pulse frequency on PC14 reaches about 8.0 MHz:

272323415-cb7b5caf-7e21-4bfa-a6c6-c5d41f34b8a6

For SYSCLK = 120 MHz, the output pulse frequency on PC14 reaches about 8.62 MHz:

272323439-e707a410-fef1-4941-82ba-628c6b53bb7d

For SYSCLK = 128 MHz, the output pulse frequency on PC14 reaches about 9.17 MHz:

272323488-d005036b-e9ed-40c7-8c18-ef32f3d984f1

128 MHz was the highest clock frequency achievable with an 8 MHz crystal. Therefore, we change the external crystal to 16 MHz so that we can reach higher clock frequencies.

272330538-33f3ca02-53d7-43d8-b7e8-4d9710d3b592

After configuring the project for SYSCLK = 144 MHz, the output pulse frequency on PC14 increases to approximately 10.25 MHz.

272323571-58dff154-c042-475d-a193-3547b6c880b5

The frequency of 10.25 MHz is the highest frequency that the output remains stable for at least 10 minutes.

Now we configure the project for SYSCLK = 160 MHz. In this case, the output pulse frequency on PC14 reaches about 11.47 MHz, but after about 20 seconds, it becomes unstable and the output is cut off.

272323640-4c23c660-227e-40a5-a059-5ee8ab06594d

From now on, by increasing the clock frequency, we do not see any pulses on PC14, which indicates that the microcontroller is not functioning properly and it is not possible to increase the clock frequency anymore.

Solution 2

By changing the code and using the EORS instruction instead of EOR, the output frequency increased slightly. The results are as follows:

asm volatile(
  "eors r1, r2\n"  // XOR the last value of GPIOC_ODR (r1) with the mask (r2)
  "str r1, [r0]\n" // Store the new value (r1) back to the address of GPIOC_ODR
);

External crystal = 8 MHz, SYSCLK = 128 MHz, output frequency on PC14 = 10.64 MHz stable:

272329966-896e1fd8-91a3-48c1-ac06-57b7887ba799

External crystal = 16 MHz, SYSCLK = 144 MHz, output frequency on PC14 = 12.05 MHz stable:

272329999-6fffa32e-d92c-4eac-a8f7-8cba81678187

External crystal = 16 MHz, SYSCLK = 160 MHz, output frequency on PC14 = 13.33 MHz Unstable (lasts only about 20 seconds):

272330094-6384566f-a16d-43df-b01d-5dd7a625acd3

Solution 3

To increase the pulse frequency, before entering the while loop, the corresponding values for GPIOC_ODR to set the PC14 pin to 0 and 1 is stored in two genral-purpose registers r1 and r2:

asm volatile(
  "ldr r0, =0x4001100C\n" // Load GPIOC_ODR address into register r0
  "ldr r1, =0x00000000\n" // Move the value for PC14 = 0 into register r1
  "ldr r2, =0x00004000\n" // Move the value for PC14 = 1 into register r2
);

Inside the while loop, we use two STR commands to set PC14 to zero and one.

asm volatile(
  "str r2, [r0]\n" // Store value of r2 (PC14 = 1) to the address of GPIOC_ODR
  "str r1, [r0]\n" // Store value of r1 (PC14 = 0) to the address of GPIOC_ODR
);

Now, with an external crystal of 16 MHz and SYSCLK = 144 MHz, a frequency of 20.66 MHz can be reached on PC14:

272334031-7472b35f-3f81-4bf9-8d92-e28eec869349

The branch instruction b executed at the end of each while loop, reduces the frequency of output pulse on PC14;

272334330-4bdf354d-4d27-4ff4-b20d-91210b51f5e8

To solve this problem, we toggle PC14 multiple times and sequentially in each execution of the loop:

272334366-a43d2e2e-fb9f-4e71-b1c0-dcd5944fdd60

By removing the delay caused by the branch, we were able to reach a frequency of 36.23 MHz on PC14 with an external crystal of 16 MHz and setting the system clock to 144 MHz:

272334416-d7bea841-1a9d-40dc-a2cc-a9fab940eaa7

Solution 4

The EVENTOUT function on PC14 pin can be used to achieve higher frequency. After enabling the EVENTOUT function, the value of PC14 can be set to 1 only for one clock cycle using the SEV instruction. In this way, half of a full pulse is created. Now, with the help of the NOP instruction, we create a delay for one clock cycle in the state where the value of PC14 is 0, so that a complete pulse is created.

272402690-35acc2ad-6d8f-4805-8509-ccb1999204ec

asm volatile(
  "sev\n" // Set EVENTOUT pin (PC14) for one clock (and then reset it) => PC14 =1
  "nop\n" // Wait for one clock cycle and do nothing (while EVENTOUT is reset) => PC14 = 0
);

Similar to solution 3, it is possible to eliminate the delay caused by branch instruction b in the generated signal by sequentially executing SEV and NOP inside the while loop. The results of this program are as follows:

External crystal = 8 MHz, SYSCLK = 128 MHz, output signal frequency = 64.10 MHz:

272402498-a064a292-957b-4ec5-9bb9-a1f6d6c7f3df

External crystal = 16 MHz, SYSCLK = 128 MHz, output signal frequency = 64.10 MHz:

272402476-352d359a-ea74-4bd3-ac1b-2fcbf6f8c437

External crystal = 16 MHz, SYSCLK = 144 MHz, output signal frequency = 72.46 MHz (highest stable frequency):

272402450-ce426b2e-4062-42c0-b00f-563a52a3fde5

As you can see, the quality and amplitude of the output signal is still not very good. To increase the quality of the output signal, it is necessary increase clock frequencies of all involving microcontroller units to their highest level. For this purpose, changes were made in the code as follows:

PC14 settings:

unnamed

Clock settings for 8 MHz crystal:

unnamed-1

Signal obtained on PC14 with 8 MHz crystal and SYSCLK = 128 MHz: (64.10 MHz)

unnamed

Clock settings for 16 MHz crystal:

unnamed

Signal obtained on PC14 with 16 MHz crystal and SYSCLK = 128 MHz: (64.10 MHz)

unnamed

Signal obtained on PC14 with 16 MHz crystal and SYSCLK = 144 MHz: (72.46 MHz - the highest stable frequency achievable)

unnamed-1

Solution 5

I tried to store the whole program or some parts of it in SRAM in order to prevent microcontroller from hanging in higher clock frequencies. The results after storing the whole program in SRAM was not successful, but storing the toggle_v5() in SRAM caused to get a stable signal with the frequency of 80.00 MHz while SYSCLK = 160 MHz.

I cannot explain why, but it worked for me in the first attempt and was stable for more than an hour. But in the next day, when I turned on the board, I saw that the output is unstable!

__attribute__((section(".data"))) inline void toggle_v5(void)
{
  // Toggle PC14 using EVENTOUT function
  asm volatile(
      "sev\n" // Set EVENTOUT pin (PC14) for one clock cycle (and then reset it) => PC14 = 1
      "nop\n" // Wait for one clock cycle and do nothing (while EVENTOUT is reset) => PC14 = 0
  );
}

dso_01_01_02_23_55

Resources

About

Push STM32 to its limits (Overclocking Challenge)

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages