9
\$\begingroup\$

What I was doing

I am using a STM32 microcontroller and for my project I need to be able to send data at specific times of the day (say, at 11am and 2pm). The microcontroller needs to know what time it is before I can achieve this. Unfortunately, I only have an one-way communication, and I therefore cannot request the current time from the network.

Therefore I want to set the current time, directly after I am done programming. I knew I am able to write data to the flash using the ST-LINK Utility Command Line Interface (ST-LINK_CLI) using the following command:

ST-LINK_CLI.exe -w32 <Address> <data> -Rst

I wrote a simple test script that writes the Unix time stamp to some address not currently in use by the code.

I was about to write a function to read the time-stamp and use it to set the RTC time. Until I read the following in the ST-LINK Utility User Manual:

-w32 supports writing to Flash memory, OTP, SRAM and R/W registers.

When the manual says it supports writing to the R/W registers, does this mean I can directly access the RTC registers and set them? I have tried, but I can't seem to write to these registers.

I would prefer to use this method if it does, as I would not need to write a specific function to handle it on the microcontroller anymore. This means that I can set the RTC time of any microcontroller we currently have in use, instead of needing to update their code.


What I intended to do

To set the RTC registers, I tried to do the following steps, as described in the STM Reference Manual:

  • set DPB bit in PWR_CR register
  • write 0xCA to RTC_WPR register
  • write 0x53 to RTC_WPR register
  • stop the RTC by setting the INIT bit in RTC_ISR register
  • select the 1Hz clock by writing to the RTC_PRER register
  • load the current time by writing to the RTC_TR register
  • load the current date by writing to the RTC_DR register
  • start the RTC by resetting the INIT bit in RTC_ISR register

To access the registers, I have used the following addresses:

  • PWR_CR: 0x4000 7000
  • RTC_WPR: 0x4000 2824
  • RTC_ISR: 0x4000 280C
  • RTC_PRER: 0x4000 2810
  • RTC_TR: 0x4000 2800
  • RTC_DR: 0x4000 2804

What went wrong

I am not able to write to either of these registers. With the ST-LINK Utility, I get the following message:

Error occured during memory writing!

Using the ST-LINK_CLI:

Writing 0x00000100 at 0x40007000...Error!

Reading these registers is no problem, but I cannot write to them using either the ST-LINK Utility or its Command Line Interface.


The question

How can I write to the R/W registers using the ST-LINK Utility?

Is there some kind of write protect to allow writing to the RTC registers which I overlooked?

\$\endgroup\$
  • \$\begingroup\$ Possibly write-protected unless a key-code is entered. \$\endgroup\$ – user105652 May 31 '16 at 19:05
  • \$\begingroup\$ Glad to see you have figured out a lot yourself from the initial hints. Generally you should post a solution as an answer rather than an edit to the question, and especially when you have pursued it this far yourself it would be appropriate to ultimately move your accept to that. \$\endgroup\$ – Chris Stratton Jun 3 '16 at 7:28
  • \$\begingroup\$ I actually haven't thought of it that way! I feel like I should still do so, even though I´d like you to have some credits too. \$\endgroup\$ – Spectre208 Jun 3 '16 at 7:43
  • \$\begingroup\$ How long after programming does your device have to run, and how accurate does the time of day have to be? I'm just worried that no matter how accurate you RTC is, it's eventually going to drift a little, at least if it's used for years and your timing requirements are strict. \$\endgroup\$ – Timo Jun 3 '16 at 10:19
  • \$\begingroup\$ It is supposed to run for 10 years on a single battery.. However, the time scheme already gets slightly modified by some random number to prevent all the devices from sending their data all at once. The RTC time drift is therefore no big deal. \$\endgroup\$ – Spectre208 Jun 3 '16 at 11:09
4
\$\begingroup\$

Some registers are only legal for a specific access width (ie, -w32 may not be correct), or may not read back the written values which could cause a problem with verification.

There might also be sequence or state restrictions on accessing things.

An option that should work around most conceivable issues would be to craft a tiny program to do the job which would linked to run in RAM. You could substitute the data into its binary after figuring out the offset, upload the modified version, and run it. Or you could have the program get values from a region of RAM outside of the file's extents, which you would set before running. With finer grained control of the stlink you could also pass values in CPU registers, though you might(?) need the alternate open source command line program rather than ST's to do that (this small routine in RAM method is incidentally how that program accomplishes writing to flash)

| improve this answer | |
\$\endgroup\$
3
\$\begingroup\$

So, one of the problems was, as Chris Stratton pointed out:

Some registers .. may not read back the written values which could cause a problem with verification.

This meant that the verification failed, causing the error to display, even though the write operation actually succeeded.

Below is the response I get when reading the PWR_ISR register, setting the INIT bit, then reading the register back again:

0x4000280C : 00000027

Writing 0x00000080 at 0x4000280C...Error!

0x4000280C : 000000A7

The verification of the ST-LINK Utility checks if the value written to the address and read from the address match. In this case, the write operation was successful, even though the two values don't match, as the INIT bit is now set.

The other problem was that I could not notice the effect of the write operation. While connected to the microcontroller, it gets kept in the reset state by the ST-LINK (known as "connect under reset"). I needed to use the HOTPLUG connect option, which connects to the microcontroller without halt or reset.

The “connect under reset” option allows to connect to the target before executing any instruction. This is useful in many cases like when the target contains a code that disables the JTAG/SWD pins.

The “HotPlug” option allows to connect to the target without halt or reset. This is useful to update RAM addresses or IP registers while application is running

The batch file fully works as I wanted it to! The command now looks like this:

ST-LINK_CLI.exe -c HOTPLUG -w32 <Address> <data> -w32 <Address> <data> ...
| improve this answer | |
\$\endgroup\$
1
\$\begingroup\$

I think what is happening is that after the write, a verification read is performed. If the same register returns current time in a read, although you succeed in updating the RTC, the debugger will not realise. This is less likely to explain a problem with the power register (unless the debugger is accessing that register too under the hood). Check the read value manually. If there was a more significant problem, this read might fail too. Also, try the other registers in your list.

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.