How does Husky sett MCU's clock

Hi all,

I have a Husky and I want to set the clock frequency of my ST32 target (CW308T-STM32F). I knew that one can simply set the MCU’s clock speed by scope.clock.clkgen. But does this mean I provide an external clock source to the MCU instead of the internal one (scope.clock.clkgen_src='system')? Also, I found that there is a flag call F_CPU that is used to compile a binary. Does this F_CPU has to be the same clock value I am setting for?

Thanks for your time

scope.clock.clkgen_src = 'system' means that Husky is generating the target’s clock; it’s sent over Husky’s HS2 output, and the CW308 passes that on to the target (if you set its clock selection jumpers correctly).

The other setting (scope.clock.clkgen_src = 'extclk') means that the target must generate its own clock and send it to Husky’s HS1 input. Almost all our notebooks use 'system'. But with the CW308 you can easily use a crystal to generate the clock on the target side.

For our example notebooks, when you change the target’s clock, you also need to adjust the target’s baudrate accordingly.

F_CPU is used by the target for things that need some definition of time; in our case, for our simpleserial targets, that’s the baud rate. Instead of recompiling with different F_CPU values, you can just scale target.baud accordingly. So for example, if you’re using SS_VER1, it’s meant to run at 38400 baud on the default 7.37 MHz frequency. If you double the clock to 7.37 x 2 = 14.74 MHz, then just double the baud rate: target.baud = 38400*2.

Finally, when going to higher clocks, make sure you don’t exceed your particular target’s maximum rated clock frequency (which you’ll find in its datasheet).

Thanks, it is more clear to me now. But I was shocked by the build system for the stm32 target: I was reading stm32f3_hal_lowlevel.c and got confused about setting out the clock in the code. I first found the variable uint32_t SystemCoreClock = 8000000U; in the code, and according to the comment for function HAL_RCC_ClockConfig, this is the variable to set up the MCU’s clock speed. The variable, SystemCoreClock, then can be overwritten by HAL_RCC_GetHCLKFreq function. But this function is never used. Instead, the variable is overwritten by the following-commented function:
//SystemCoreClock = HAL_RCC_GetSysClockFreq() >> AHBPrescTable[(RCC->CFGR & RCC_CFGR_HPRE)>> RCC_CFGR_HPRE_BITNUMBER];

So If I remove the comment, the variable SystemCoreClock is updated by this line which uses the F_CPU as the reference for (Function HAL_RCC_GetSysClockFreq returns F_CPU). This makes me wonder that flag F_CPU can also be used for setting the internal clock of a MCU. However, this conclusion conflicts about what you just said about the flag.

In a nutshell, what is the correct way to set the internal clock then?

F_CPU is defined here: chipwhisperer/firmware/mcu/hal/Makefile.hal at develop · newaetech/chipwhisperer · GitHub

F_CPU gets returned by HAL_RCC_GetSysClockFreq(), which in turn is used together with the defined BaudRate when the UART is configured in stm32f3_hal_lowlevel.c.

For our example firmware, you can leave F_CPU to its default 7372800 and simply scale target.baud by the same factor that you’re changing the target clock by, as I explained above.

I am not asking about F_CPU, I am asking about how to set up the MCU’s clock internally. Not using the clock generated from Husky. So what is the correct way to do it? Just change this
uint32_t SystemCoreClock = 8000000U in the code?

As I understand it, the STM32 has a fixed internal 8 MHz clock that you can use; instructions to use it are here:

1 Like

Ok, so it seems like I can change uint32_t SystemCoreClock directly in the code?

My understanding is that this clock is fixed, so no, I don’t think that changing SystemCoreClock will give you a different clock. But this code is STM’s, not ours.

Why don’t you simply generate the clock that you want from Husky? That is easy and doesn’t require you to touch the target firmware. Maybe I don’t understand what you’re trying to do; explain it to me.

My project requires an adversarial scenario that an attacker cannot access the clock pin to measure the clock speed. If we have an external clock source, that implies an attacker can measure the clock externally.

I think there are others trying to do the same thing:

So I guess it is possible to build the code with a custom clock setting. I also think some ST’s code has been changed by you too. That is why I want to know whether there is an out of box way to do this.

[UPDATE] I checked the clock tree for the MCU in STM32CubeIDE, so basically there are multiple factors that will affect the system clock. Although, by default, it is 8MHz. One can change this value by PLL, PREDiv, and AHB Prescaler together with 8MHz to generate a customized-internal clock.

Understood. In this case, since you have a CW308, you can also use a crystal of your choosing to supply the target’s clock. The CW308 gives you the option of feeding that clock to your ChipWhisperer, but if you want to sample asynchronously, you don’t have to.

CW308 clock routing options are explained here.

1 Like

One more question, does this mean an attacker can estimate the clock by measuring the pin out of the crystal?

Yes, I suppose- however regardless of its source, the clock will tend to leak into the power trace, since a lot of the power consumption is the dynamic power that occurs on clock edges.

So now I have an issue complaining that “ValueError: Could not calculate pll settings for input 68 with mul 14706” in code scope.clock.clkgen_src='extclk'.

Berfore I start the python code, I did these 2 things beforehand:

  1. On CW308, I connect HS1/IN and CLKFB such that the victim’s clock (STM32F303 board) will send to the Husky
  2. I compile the binary with the flag MCU_CLK=INT.

I then write the following code:

scope = cw.scope()

scope.clock.clkgen_freq = 8000000
scope.clock.clkgen_src = 'extclk'
scope.clock.adc_mul = 10

cw.program_target(
	scope,
	cw.programmers.STM32FProgrammer,
	'main-CWLITEARM.hex')

This complain occurs at scope.clock.clkgen_src = 'extclk'. Anything I miss to do?

The “input 68” part of the error message means that Husky is measuring the HS1 clock to be 68 Hz (in other words, ~no clock); probably because you haven’t programmed the target firmware yet.

I would do things in this order:

scope = cw.scope()
scope.default_setup()
cw.program_target(...)

scope.clock.clkgen_freq = 8e6
# etc...

If it still doesn’t work, review CW308 UFO - NewAE Hardware Product Documentation and make sure your CW308 jumpers are set correctly; if you have another scope or logic analyzer, confirm that you’re getting a good clock on the HS1 pin.

I follow what you suggested but I still get the same error.

I also did what the document said to route the victim’s clock to Husky as the picture shows:

I did have an external J-Trace debugger attached to the board; however, no matter I connected it or not, the same error still occurs. :frowning:

That is the correct jumper setting.
As I said, the next step is to verify that your target is actually producing a clock; look at the CLKFB pin of J5.
If you don’t see a clock there, use your debugger to confirm whether the correct firmware has been programmed to your target, and that it’s actually running.

How can I check the CLKFB pin? Should I use things like oscilloscope to do so?

Yes of course, or a logic analyzer.