1
0
mirror of https://github.com/rfivet/stm32bringup.git synced 2025-10-16 07:54:32 -04:00

Documentation: Replace ambiguous unicode by corresponding ANSI.

Typo it's/its.
Introduce Section 4.
This commit is contained in:
2025-10-03 14:23:32 +08:00
parent af634bfd86
commit f0445c1fbe
25 changed files with 111 additions and 103 deletions

View File

@@ -98,7 +98,7 @@ defining <b>GCCDIR</b> as some sub-processes called by <b><i>gmake</i></b> may
have issues with <b>~</b> expansion (in this case <i>ld</i>). This way
<b><i>gmake</i></b> will handle the expansion before calling the sub-processes.
<h2>Toolchains chain of events</h2>
<h2>Toolchain's chain of events</h2>
In order to generate a file that can be loaded in the micro-controller, I
need to sketch the chain of events that will take place.
<ol>

View File

@@ -73,7 +73,7 @@ SECTIONS
From this snippet I can see that not only flash and ram parameters but also
the entry point for code execution, <b>Reset_Handler</b>, needs to be provided.
<p>
As a check, lets change the link script to <b>nokeep.ld</b> in <b>Makefile</b>
As a check, let's change the link script to <b>nokeep.ld</b> in <b>Makefile</b>
and generate an executable <b>.elf</b> from the empty source code file
<b>empty.c</b>:
@@ -92,7 +92,7 @@ rm empty.o
The linker gives a warning and fallback on a default address as entry point.
<p>
So lets create <b>boot.c</b> with an idle loop as <b>Reset_Handler</b>:
So let's create <b>boot.c</b> with an idle loop as <b>Reset_Handler</b>:
<pre>
void Reset_Handler( void) {
for( ;;) ;

View File

@@ -2,11 +2,11 @@
<html lang="en">
<head>
<meta charset="UTF-8">
<title>1.3 Flash Boot Debug</title>
<title>1.3 Flash - Boot - Debug</title>
<link type="text/css" rel="stylesheet" href="style.css">
</head>
<body>
<h1>1.3 Flash Boot Debug</h1>
<h1>1.3 Flash - Boot - Debug</h1>
Now that I have an executable bootstrap, I need to flash an actual board
with it to check if it works as expected. On a member of the STM32F030
@@ -48,7 +48,7 @@ Referenced as
<a href="https://www.st.com/content/st_com/en/products/development-tools/software-development-tools/stm32-software-development-tools/stm32-programmers/stm32cubeprog.html">
STM32CubeProg</a>
on STMicroelectronics website, the STM32 Cube Programmer comes with USB
drivers and a firmware upgrade utility for the ST-Link. Its a java
drivers and a firmware upgrade utility for the ST-Link. It's a java
based application with available distribution for Win32, Win64, Mac and Linux.
There are regular updates to support the latest chipsets. I am currently
using version v2.17.0.

View File

@@ -88,7 +88,7 @@ through the frames gives me a better estimation.
<h2>Checkpoint</h2>
This is just a small increment on my previous step, but thats iterative
This is just a small increment on my previous step, but that's iterative
development in a nutshell. Also I didn't come with a reasonable value
for the delay counter at first, it's easy to underestimate how fast
micro-controllers are.

View File

@@ -8,12 +8,12 @@
<body>
<h1>1.6 The Tick</h1>
<img alt="Its blue! It blinks! Its the Tick!" src="img/16_tick.png">
<img alt="It's blue! It blinks! It's the Tick!" src="img/16_tick.png">
<p>
In previous iteration, I made the user LED blink using an active delay
loop. I have two issues with this implementation:
<ul>
<li> Its hard to control the delay timing accurately
<li> It's hard to control the delay timing accurately
</ul><ul>
<li> Active loops are not cool
</ul>
@@ -34,7 +34,7 @@ while( enabled) {
}
</pre>
Its an auto decremented counter that reloads and sets a flag when
It's an auto decremented counter that reloads and sets a flag when
reaching zero. It can trigger a system interrupt if requested to. Its
default clock is the processor clock and can be switched to external
clock. Details can be found in the Programming Manual as this is part of
@@ -50,7 +50,7 @@ from <b>Reset_Handler</b> to <b>SysTick_Handler</b>.
</ul><ul>
<li> Introduce the <b>SysTick</b> core peripheral to the compiler, using
pre-processor macroes to give the location of SysTick registers. As this
is a core peripheral, its in a different address space than the
is a core peripheral, it's in a different address space than the
peripherals I have seen so far.
</ul><ul>
<li> Start the <b>Reset_Handler</b> by initializing and enabling the System
@@ -126,7 +126,7 @@ void SysTick_Handler( void) {
}
</pre>
I didnt initialize the GPIO B before enabling the SysTick as I have a
I didn't initialize the GPIO B before enabling the SysTick as I have a
whole second before the first interrupt will tick in.
<p>
Build is straightforward.

View File

@@ -205,8 +205,8 @@ If I look further in the <b>cstartup.map</b> generated by the linker.
<li> <code>i</code> is located in <b>.bss</b> at 0x20000008
<li> <code>c</code> is not listed as it doesnt have global scope, but I can
guess its located at 0x20000000.
<li> <code>c</code> is not listed as it doesn't have global scope, but I can
guess it's located at 0x20000000.
<li> Initial values for the <b>.data</b> section are located at 0x0800007c.
</ul>

View File

@@ -251,7 +251,7 @@ Building shows an increase in code, still no data.
<p>
Once <b>f030f4.hex</b> is loaded into the board, the behavior is the same
as <b>ledtick.hex</b>. The new file structure and data initialization
didnt introduce any <del>bugs</del> changes, just code overhead.
didn't introduce any <del>bugs</del> changes, just code overhead.
<h2>Checkpoint</h2>

View File

@@ -15,13 +15,13 @@ to validate that I have working hardware and software tools.
<h2>Board Connectivity</h2>
Even if the peripheral is capable of doing synchronous communication
(thats the S in USART), asynchronous communication (thats the A) which
(that's the S in USART), asynchronous communication (thats the A) which
only needs 3 wires (GND, TX, RX, (no clock)) is usually what is needed
in non specialized cases.
<p>
Boards sold online often have dedicated pre-soldered pins for UART
connectivity similar to what I have seen before for the SWD interface.
The VCC-GND board I used previously doesnt have such dedicated pins but the
The VCC-GND board I used previously doesn't have such dedicated pins but the
functionality is wired on the pins PA9 (<b>TX</b>) and PA10 (<b>RX</b>).
<p>
I will use a board with dedicated pins (GND, TX, RX, VCC 3.3V). Board

View File

@@ -58,7 +58,7 @@ refer directly to <code>GPIO( LED_IOP)[ MODER]</code>.
I use conditional compilation based on <code>LED_ON</code>. If
<code>LED_ON</code> is high, I need an extra step during initialization
compare to <code>LED_ON</code> low. On the other hand, if <code>LED_ON</code>
is undefined, the code would be removed for a board that doesnt have a user
is undefined, the code would be removed for a board that doesn't have a user
LED.
<pre>

View File

@@ -8,7 +8,7 @@
<body>
<h1>2.3 Hello There!</h1>
Looking for a <i>“you had me at hello”</i> moment?&nbsp; Lets see how serial
Looking for a <i>“you had me at hello”</i> moment?&nbsp; Let's see how serial
transmission works for you.
<h2>Implementation</h2>
@@ -55,11 +55,11 @@ To check if it is ready for transmission you must check the state of the
TX Empty (<b>TXE</b>) bit in the Interrupt & Status Register (<b>ISR</b>).
<p>
I write a basic <code>kputc()</code> function that does busy waiting if the
<b>TDR</b> is not empty and insures that LF are mapped to CR LF. The k in
kputc refer to kernel, as kputc is a low level function that will be used
<b>TDR</b> is not empty and insures that LF are mapped to CR LF. The 'k' in
kputc refer to 'kernel', as kputc is a low level function that will be used
mostly for debugging. With the busy wait and the recursive code this
implementation is definitively not optimal, but its functional and
thats what matter most at this stage.
implementation is definitively not optimal, but it's functional and
that's what matter most at this stage.
<pre>
void kputc( unsigned char c) {
@@ -131,8 +131,8 @@ as usual but I can see the RX LED on the USB to UART adapter flash
briefly when I release the reset button.
<p>
On Windows PC, if I use PuTTY or Arduino IDE to open <b>COM4</b> at 9600
baud, every time I press and release the reset button I can see hello,
world displayed on a new line in the terminal window.
baud, every time I press and release the reset button I can see 'hello, world'
displayed on a new line in the terminal window.
<p>
On Linux, when I plug in the USB to UART adapter, it enumerates as
<b>/dev/ttyUSB0</b>, so it is compatible with the USB driver for serial
@@ -144,7 +144,7 @@ writing.
Once added to <b>dialout</b>, I can open <b>/dev/ttyUSB0</b> at 9600 baud in
Arduino IDE, each time I press and release the board RESET button, I can see
hello, world displayed on a new line in the Serial Monitor window.
'hello, world' displayed on a new line in the Serial Monitor window.
<h2>Checkpoint</h2>

View File

@@ -33,7 +33,7 @@ Receiving objects: 100% (1357/1357), 1.04 MiB | 74.00 KiB/s, done.
Resolving deltas: 100% (912/912), done.
</pre>
Build on Linux doesnt show any warnings.
Build on Linux doesn't show any warnings.
<pre>
$ cd stm32flash-code
@@ -130,7 +130,7 @@ case <b>COM4</b> instead of <b>/dev/ttyUSB0</b>.
There is several other Windows applications available on ST.com for
flashing STM32 chipsets: STM32 ST-Link Utility, STM32 Flash Loader
Demonstrator, ST Visual Programmer STM32. They have been marked as <b>NRND</b>
(Not Recommended for New Design), which means they wont support latest
(Not Recommended for New Design), which means they won't support latest
chipsets as they are replaced by STM32 Cube Programmer.
<p>
<a href="25_prototype.html">Next</a>, I will write an application which make

View File

@@ -8,7 +8,7 @@
<body>
<h1>2.6 uptime</h1>
Its time to throw away the prototype and write a production version of
It's time to throw away the prototype and write a production version of
<code>uptime</code>. There is several things I want to straighten up in
<b>uptime.1.c</b>:
<ul>
@@ -50,13 +50,13 @@ Next, I make a revision of <b>uplow.1.c</b> by making a copy into
I include <b>system.h</b> which is the interface that <b>uplow.2.c</b>
implements. I will have several implementations of the same interface,
so <b>system.h</b> is not just the interface published by <b>uplow.2.c</b>,
its <b>uplow.2.c</b> which is an implementation of <b>system.h</b>.
it's <b>uplow.2.c</b> which is an implementation of <b>system.h</b>.
<pre>
#include "system.h" /* implements system.h */
</pre>
I extract the code for <b>puts()</b> as it is a library function that doesnt
I extract the code for <b>puts()</b> as it is a library function that doesn't
really belong to the system.
<p>
I add the implementation of <b>kputs()</b> and <b>yield()</b>.
@@ -90,7 +90,7 @@ version by adding characters at the beginning of a string.
<li> <code>kputu()</code> takes one additional divider parameter, so it can be
used to print unsigned integer in various format like octal, decimal and
hexadecimal. Current implementation will work for base 8 to 16, it wont
hexadecimal. Current implementation will work for base 8 to 16, it won't
work for binary or base 36.
<li> <code>kputi()</code> outputs signed integer.
@@ -256,7 +256,7 @@ The linker found a reference to <code>putchar()</code> at line 41 of
printf( "\n") ;
</pre>
I havent used <code>putchar()</code> in my code and line 41 is a
I haven't used <code>putchar()</code> in my code and line 41 is a
<code>printf( "\n")</code> that can be optimized to a
<code>putchar( '\n')</code>. This must be some high level C optimization of gcc.
<p>
@@ -324,7 +324,7 @@ I flash the board and start execution, the output works as expected.
<img alt="uptime" src="img/26_uptime.png">
<p>
It will take a while to see the days and weeks counts appear, so I will
need to power the board independently from its serial interface. For
need to power the board independently from its serial interface. For
test purpose I fast forward the execution by using a bigger value for
the increment of <code>uptime</code> in <code>SysTick_handler()</code>.
@@ -332,11 +332,11 @@ the increment of <code>uptime</code> in <code>SysTick_handler()</code>.
Rereading the code while writing this web page, I found a typo in the
week calculation. After that I retested with a bigger time increment to
make sure days and weeks values are correct. Its also clear that the
make sure days and weeks values are correct. It's also clear that the
test coverage for the printf format interpreter is not sufficient as I have
coded more than is necessary to implement <b>uptime</b>.
<p>
I didnt expect gcc to optimize calls to high level C functions,
I didn't expect gcc to optimize calls to high level C functions,
replacing some <code>printf()</code> by <code>putchar()</code>, thus forcing me
to write additional code. So far I am not concerned by execution speed, so this
type of optimization is a bit counter productive.

View File

@@ -9,7 +9,7 @@
<h1>2.7: C Library</h1>
So far I have used three Standard C library functions for output:
<code>printf()</code>, <code>putchar()</code> and <code>puts()</code>. Its
<code>printf()</code>, <code>putchar()</code> and <code>puts()</code>. It's
time to bundle them as a library. This will give me more flexibility as I will
not have to give a full list of the modules to link, the linker will handle
the missing dependencies by looking into the libraries.
@@ -38,7 +38,7 @@ int puts( const char *s) {
I need to tell <b>GNU make</b> how to manage and use the library, which
means updating <b>Makefile</b> with the following informations:
<p>
Whats the name, the content and the rule to maintain the library:
What's the name, the content and the rule to maintain the library:
<pre>
AR = $(BINPFX)ar
@@ -63,7 +63,7 @@ $(PROJECT).elf: $(OBJS) lib$(LIBSTEM).a
$(OBJDUMP) -hS $@ > $(PROJECT).lst
</pre>
Library modules are implicitly part of the composition, so its not
Library modules are implicitly part of the composition, so it's not
necessary to list them anymore.
<pre>

View File

@@ -9,7 +9,7 @@
<h1>2.8 Baud Rate and Clocks</h1>
<blockquote> “The time has come,” the walrus said, “to talk of many things: Of baud
rates and clocks and quartz.”<br>
rates - and clocks - and quartz.”<br>
-- Les huit scaroles --
</blockquote>
@@ -20,7 +20,7 @@ so how fast is that?
<h2>A bit of theory</h2>
Lets interpret asynchronous serial transmission, 9600 baud, 8 bits, no
Let's interpret asynchronous serial transmission, 9600 baud, 8 bits, no
parity, 1 stop bit.
<ul>
<li> Serial transmission means transmission on one wire, with each bit sent
@@ -40,17 +40,17 @@ the change in the wire state.
</ul>
In my case, <b>8N1</b> means that, because of the framing pattern, for
every byte of data sent, there is one extra start bit and one extra stop
bit sent, its ten bits per byte of data. At 9600 bauds that means 960
bytes per second, fast enough to transmit every characters of a 80×24
bit sent, it's ten bits per byte of data. At 9600 bauds that means 960
bytes per second, fast enough to transmit every characters of a 80x24
terminal screen in two seconds.
<h2>Baud rate accuracy</h2>
It sounds like a pretty robust transmission scheme, sampling at 16 times
the transmission clock isnt call oversampling for nothing. Am I
the transmission clock isn't call oversampling for nothing. Am I
overdoing something here or just compensating for something I missed?
<p>
The thing is, I didnt program USART1 to transmit at 9600 baud. As my
The thing is, I didn't program USART1 to transmit at 9600 baud. As my
default clock is 8MHz, I had to write in USART1 baud rate register a
value close to 8000000/9600 or 2500/3, 833 is close enough but my actual
transmission speed is closer to 9604, slightly faster than 9600 baud.
@@ -62,7 +62,7 @@ want to work at higher baud rate.
<h2>Clocks</h2>
Looking at the clock tree in the datasheet can be intimidating, its
Looking at the clock tree in the datasheet can be intimidating, it's
definitively about several clocks.
<p>
<img alt="Clock Tree" src="img/28_clocktree.png">
@@ -115,7 +115,7 @@ I will use 24 MHz.
<h2>Quartz</h2>
I can also activate the quartz if there is one soldered on the board.
Its usually the case but specially for STM32F030F4 which has only 20
It's usually the case but specially for STM32F030F4 which has only 20
pins, a quartz less design that free up two GPIO pins can be a day
saver. Quartz value from 4 to 32 MHz are supported and most design use 8
MHz.

View File

@@ -8,7 +8,7 @@
<body>
<h1>2.9 Interrupt Driven Transmission</h1>
Its time to revise the implementation of <code>kputc()</code>, remove the
It's time to revise the implementation of <code>kputc()</code>, remove the
recursive call to handle CR LF transmission and avoid the busy wait
loop. USART1 can trigger an interrupt when the Transmit Data Register
(<b>TDR</b>) is empty which is all I need to implement interrupt driven
@@ -128,7 +128,7 @@ Configuration Register of USART1:
<pre>#define USART_CR1_TXEIE (1 << 7) /* 7: TDR Empty Interrupt Enable */</pre>
I use a Round Robin buffer to synchronize <code>kputc()</code> and
<code>USART1_Handler()</code> making sure they dont write to the same location.
<code>USART1_Handler()</code> making sure they don't write to the same location.
<pre>
static unsigned char txbuf[ 8] ; // best if size is a power of 2 for cortex-M0
@@ -141,11 +141,11 @@ static volatile unsigned char txbufout ;
<code>USART1_Handler()</code> only read from it.
<li> <code>txbufin</code> is the index of the position where
<code>kputc()</code> will insert a character, its written by
<code>kputc()</code> will insert a character, it's written by
<code>kputc()</code> and read by <code>USART1_Handler()</code>.
<li> <code>txbufout</code> is the index of the position where
<code>USART1_Handler()</code> will fetch a character, its written by
<code>USART1_Handler()</code> will fetch a character, it's written by
<code>USART1_Handler()</code> and read by <code>kputc()</code>. The value of
<code>txbufout</code> will change under interrupt, so it is marked as
<code>volatile</code> to make sure the compiler will not optimize the code in a
@@ -260,7 +260,7 @@ to hold lastc (1 byte). The new version uses 12 bytes to hold the round robin
buffer (8 bytes), its in and out indexes (2 bytes) and lastc (1 byte).
<li> The compiler optimizes the modulo instruction in <code>% size</code> to
bit masking <code>& (size 1)</code> as the size 8 is a power of 2.
bit masking <code>& (size - 1)</code> as the size 8 is a power of 2.
</ul>
Flashing a device with the new executable, <b>uptime</b> works as the previous
version.

View File

@@ -11,7 +11,7 @@
The DHT11 is a low cost humidity and temperature sensor from Aosong
which is easy to buy online. It is not popular as it has a non standard
communication protocol and its precision is ±5% for humidity and ±2°C
for temperature so its often overlooked for more expensive solution.
for temperature so it's often overlooked for more expensive solution.
<h2>Hardware consideration</h2>
@@ -142,11 +142,11 @@ iolvl_t gpioa_read( int pin) { /* Read level of GPIOA pin */
}
</pre>
I didnt use the GPIO Input Data Register (<b>IDR</b>) until now, so I add it
I didn't use the GPIO Input Data Register (<b>IDR</b>) until now, so I add it
to the registers description.
<p>
<code>gpioa_output()</code> implementation is minimal. I know I am switching
only between input and output mode, so I dont need to mask the bit field
only between input and output mode, so I don't need to mask the bit field
first.
<p>
I use the System Tick to implement <code>usleep()</code>.
@@ -165,7 +165,7 @@ The System Tick generates an interrupt every second but I can read the
Current Value Register (<b>CVR</b>) to pause for smaller time period.
<p>
As I will read the sensor just after a new second count, I know that the
<b>CVR</b> value is close to maximum and I dont need to care for a roll
<b>CVR</b> value is close to maximum and I don't need to care for a roll
over.
<p>
SysTick input clock is <b>HCLK/8</b>, this implementation will work for
@@ -331,7 +331,7 @@ can measure 80µs in retries unit. This is all I need to calibrate the timing
measurement.
<p>
I can do this calibration every time the DHT11 starts transmission, this
way I dont need to update some constant if I change the frequency of my
way I don't need to update some constant if I change the frequency of my
system clock.
<pre>
@@ -418,7 +418,7 @@ two seconds.
<p>
<img alt="DHT11 output" src="img/31_output.png">
<p>
The humidity value seems off the mark. So I need to investigate whats
The humidity value seems off the mark. So I need to investigate what's
the issue.
<h2>Checkpoint</h2>

View File

@@ -9,7 +9,7 @@
<h1>3.2 DHT11 Errata</h2>
I only did basic testing so far, checking that the values read were
displayed properly. But the humidity values didnt seem correct, so I
displayed properly. But the humidity values didn't seem correct, so I
need to do some extra verifications. There are many possible causes and
they can combine, bugs like humans are social animals, when you find
one, look for its mates.
@@ -55,7 +55,7 @@ the previous version v1.3 branded AOSONG which seems identical except a
revision page.
<p>
I also have an English Aosong DHT11 datasheet that seems outdated.
Aosong doesnt seem to allow redistribution of their datasheet so most
Aosong doesn't seem to allow redistribution of their datasheet so most
online vendor have made their own based on that English version.
<p>
The English datasheet states the temperature range as 0~50℃, the
@@ -80,7 +80,7 @@ around 25~26%RH. As I have changed both interval and setup time, I need
confirm that it is the interval time that matters.
<p>
With intervals of 5 and 6 seconds, the reading jumps above 37%RH. So
its clearly a problem with the interval.
it's clearly a problem with the interval.
<p>
I want to make a round number of samples per minute, so I need retest to
check if 10 and 12 seconds work the same as 15, but before I do fine
@@ -89,7 +89,7 @@ particular DHT11.
<h2>Product quality</h2>
Its clear that the DHT11 I am testing is not behaving according to old
It's clear that the DHT11 I am testing is not behaving according to old
or new specifications for the sampling interval.
<p>
Defects happen! No production line output is 100% perfect, so I may just
@@ -205,14 +205,14 @@ And retest after the following modification.
<h2>Stability</h2>
During my test I didnt noticed big surges in measurements but the time
During my test I didn't noticed big surges in measurements but the time
to get to actual value is quite long. The interval between readings
affects the measurement and initially it takes a long time for the
readings to converge to actual temperature or humidity.
<h2>Conclusions</h2>
I didnt find any English version of the latest version of the
I didn't find any English version of the latest version of the
datasheet.
<p>
I found some difference between the Chinese datasheet and the behavior

View File

@@ -24,7 +24,7 @@ resistor between vcc and io data.
<img alt="DS18B20 Board" src="img/33_ds18b20.png">
</p>
It is possible to power the chip using data io and gnd only (no vcc) in
Parasitic Power Mode if a two wire only interface is needed. I wont use
Parasitic Power Mode if a two wire only interface is needed. I won't use
this feature for now.
<h2>Communication protocol</h2>

View File

@@ -81,7 +81,7 @@ The ADC characteristics in the STM32F030 datasheet states that the
maximum ADC sampling clock is 14MHz. It is possible to select either an
internal 14 MHz clock (HSI14) or PCLK divided by 2 or 4. I want to check
how the clock affects the readings (HSI14, 28/2, 24/2, 48/4). At first I
couldnt manage to make PCLK/4 work until I found the note on ADC
couldn't manage to make PCLK/4 work until I found the note on ADC
calibration work around in the errata
<a href="https://www.st.com/content/st_com/en/search.html#q=%20ES0219-t=resources-page=1"
>ES0219 2.5.3</a>
@@ -117,7 +117,7 @@ The raw data readings are relative to the analog operative voltage VDDA.
<b>Vmeasured = VDDA * VRAW / 4095</b>
<p>
This is why I measure both voltage and temperature. Ideally, VDDA should
be 3.3V, in practice its highly dependent of the power supply.
be 3.3V, in practice it's highly dependent of the power supply.
<p>
Every chip is calibrated in factory during production, ADC conversion is
done at 3.3V and 30℃ and the resulting values are stored in system

View File

@@ -17,13 +17,13 @@ reading at 3.3V (±10mV) and 30℃ (±5℃).
<img alt="TS_CAL1" src="img/34_tscal1.png">
<p>
There is only one point calibration documented and its reference
temperature is known with a precision of ±5℃. Thats not enough to
temperature is known with a precision of ±5℃. That's not enough to
calculate temperature but it shows that the sensor was tested in
production.
<p>
Notice that the calibration value name is <b>TS_CAL1</b>, some other STM32
chipset families do have a second temperature factory calibration point
<b>TS_CAL2</b>. Also some dont have any factory calibration stored at all.
<b>TS_CAL2</b>. Also some don't have any factory calibration stored at all.
So you have to refer to the datasheet that matches the chip you are
targeting when you port your code to a new chipset.
<p>
@@ -37,7 +37,7 @@ typical average slope of <b>4.3 mV/℃</b> and was calibrated in factory at
exactly <b>3.3V</b> and <b>30℃</b>, then you could use the following formula
to calculate the temperature.
<p>
<b>T = 30 + (TS_CAL1 * 3.3 TS_RAW * VDDA) / 4095 / 0.0043</b>
<b>T = 30 + (TS_CAL1 * 3.3 - TS_RAW * VDDA) / 4095 / 0.0043</b>
<p>
with
<p>
@@ -45,7 +45,7 @@ with
<p>
that gives
<p>
<b>T = 30 + 3.3 * (TS_CAL1 TS_RAW * V_CAL / V_RAW) / 4095 / 0.0043</b>
<b>T = 30 + 3.3 * (TS_CAL1 - TS_RAW * V_CAL / V_RAW) / 4095 / 0.0043</b>
<p>
If I express the average slope in raw ADC units per ℃ instead of mV/℃
<p>
@@ -53,7 +53,7 @@ If I express the average slope in raw ADC units per ℃ instead of mV/℃
<p>
the final formula is
<p>
<b>T = 30 + (TS_CAL1 TS_RAW * V_CAL / V_RAW) * 1000 / 5336</b>
<b>T = 30 + (TS_CAL1 - TS_RAW * V_CAL / V_RAW) * 1000 / 5336</b>
<p>
which matches the sample code for temperature computation given in the
reference manual (RM0360 A.7.16).
@@ -76,7 +76,7 @@ If I use the raw ADC readings from my last run
<p>
<b>VDDA = 3.3 * 1526 / 1538 = 3.274V</b>
<p>
<b>t = 30 + (1721 1718 * 1526 / 1538) * 1000 / 5336 = 33.07℃</b>
<b>t = 30 + (1721 - 1718 * 1526 / 1538) * 1000 / 5336 = 33.07℃</b>
<p>
I confirm the voltage with a voltmeter (measured 3.282V versus 3.274V
computed). The computed internal temperature value is roughly 5℃ higher
@@ -94,7 +94,7 @@ Memory (3KB) and the option bytes.
| RAM Memory | 0x20000000 | 4KB |
</pre>
The calibration data are saved in the last 96 bytes of the System
Memory, starting at address 0x1FFFF7A0. So its simple to dump the
Memory, starting at address 0x1FFFF7A0. So it's simple to dump the
content of that zone and compare the values for multiple chips.
<pre>
@@ -136,7 +136,7 @@ temperature += 30;
Factoring in the actual measured voltage, this gives
<p>
<b>T = 30 + (TS_CAL1 TS_RAW * V_CAL / V_RAW) * 80 / (TS_CAL1 TS_CAL2)</b>
<b>T = 30 + (TS_CAL1 - TS_RAW * V_CAL / V_RAW) * 80 / (TS_CAL1 - TS_CAL2)</b>
<p>
If I use the raw ADC readings from my last run
@@ -145,7 +145,7 @@ TSCAL2_SLOPE = (1721 - 1297) / 80 = 5.3 ADC step/℃
= 3.3 * 5.3 / 4095 = 4.271 mV/℃
</pre>
<b>t = 30 + (1721 1718 * 1526 / 1538) * 80 / (1721 1297) = 33.09℃</b>
<b>t = 30 + (1721 - 1718 * 1526 / 1538) * 80 / (1721 - 1297) = 33.09℃</b>
<p>
Which is only 0.02℃ higher than the previous result based on the more
generic formula. Because the temperature measured is close to the

View File

@@ -61,7 +61,7 @@ f030f4.elf from startup.txeie.o adc.o adcmain.o
2644 0 16 2660 a64 f030f4.elf
</pre>
<p>
As I dont want to turn off size optimization and I am not willing to
As I don't want to turn off size optimization and I am not willing to
always pay the full 180 bytes for a production ready <code>memset()</code>
when it is called only once at startup to clear a few bytes, I ended up adding
my own version of <code>memset()</code> to my local library.

View File

@@ -17,7 +17,7 @@ the code in flash memory.
<pre>stm32flash -g 0 COM6</pre>
With my current code, this works fine as far as I dont use interrupt
With my current code, this works fine as far as I don't use interrupt
subroutine. <b>ledon</b> and <b>blink</b> both work, but <b>ledtick</b> will
reset once the <code>SysTick_Handler()</code> interrupt routine is triggered
for the first time. This is due to the fact that the system memory is still
@@ -87,7 +87,7 @@ the resulting <b>f030f4.map</b> file.
<li> .data and .bss are located from 0x20000000.
</ul>
Lets write this code in RAM and execute it!
Let's write this code in RAM and execute it!
<pre>
stm32flash -w blink.bin -S 0x20000800 COM6
@@ -95,7 +95,7 @@ stm32flash -g 0x20000800 COM6
</pre>
This work just fine but of course the executable of <b>ledon</b> or
<b>blink</b> doesnt use interrupt routines.
<b>blink</b> doesn't use interrupt routines.
<h2>ISR Vector in RAM</h2>

View File

@@ -8,7 +8,7 @@
<body>
<h1>3.9 Reading a Resistor Value</h1>
I used the ADC previously to read the internal sensors, so its simple
I used the ADC previously to read the internal sensors, so it's simple
to move on to external ones. Once you can read the value of a resistor,
there is a wide choice of analog applications: thermistors, photocells,
potentiometers, sliders, joysticks …
@@ -35,11 +35,11 @@ in the range [0 … 4095], I can express the two voltages in terms of ADC values
<p>The voltage divider relationship now becomes<br>
&nbsp;<b><i>VDDA</i> * ADCraw / 4095 = <i>VDDA</i> * Rref / (Rref + Rmeasured)</b>
<p>which can be further simplified as<br>
&nbsp;<b>ADCraw * Rmeasured = Rref * (4095 ADCraw)</b>
&nbsp;<b>ADCraw * Rmeasured = Rref * (4095 - ADCraw)</b>
<p>The resistor value is then given by<br>
&nbsp;<b>Rmeasured = Rref * (4095 ADCraw) / ADCraw</b><br>
&nbsp;<b>Rmeasured = Rref * (4095 - ADCraw) / ADCraw</b><br>
or<br>
&nbsp;<b>Rmeasured = Rref * (4095 / ADCraw 1)</b>
&nbsp;<b>Rmeasured = Rref * (4095 / ADCraw - 1)</b>
<h2>Devil in the whatnots</h2>
Some of the things to pay attention to while coding
@@ -121,6 +121,10 @@ I add the composition in <b>Makefile</b>
<p>
Building up on the previous ADC reading of internal sensors, sampling of
an external resistor pair connected to one of the IO pin is straightforward.
</p>
<p>
<a href="index.html#part4">Next</a>, I will show the temperature readings on a
display.
</p>
<hr>© 2020-2025 Renaud Fivet
</body>

View File

@@ -39,21 +39,21 @@ $ stm32flash -r - -S 0x1FFFF7a0:96 COM6 2>/dev/null | hexdump -C
<pre>
| BootID | X | Y | Wafer | Lot | TS_CAL1 | VREFINT_CAL | TS_CAL2 | Flash | TBD |
|--------|-------|-----|-------|-----------|---------|-------------|---------|-------|---------|
| x10 | x800A | x41 | x08 | QMY687 | x6E6 | x5F1 | x53E | 16 | hZE? |
| x10 | x800C | x18 | x01 | QRR259 | x6E3 | x5F2 | x532 | 16 | h\E? |
| x10 | x8011 | x49 | x0E | W3U795 | x6D1 | x5F0 | x523 | 16 | hbF? |
| x10 | x8014 | x20 | x13 | W3R171 | x6CE | x5F5 | x527 | 16 | hd&lt;? |
| x10 | x8015 | x21 | x13 | W4A195 | x6DA | x5EE | x52A | 16 | h^D? |
| x10 | x1C | x3A | x12 | W4A820 | x6B9 | x5F6 | x511 | 16 | hR;? |
| x10 | x09 | x4D | x0B | W4C593 | x6E6 | x5F4 | x53C | 16 | haG? |
| x10 | x1D | x41 | x12 | W4R342 | x6E4 | x5F1 | x535 | 16 | hZJ? |
| x10 | x10 | x17 | x05 | WAA390 | x6E9 | x5F8 | x523 | 16 | hY=? |
| x10 | xDDC1 |xDDC1| x0D | | x703 | x5E9 | x535 | 32 | hNb\xFF |
| x10 | xDDC1 |xDDC1| x0F | | x70B | x5EF | x537 | 32 | hHX\xFF |
| x10 | xDDC1 |xDDC1| x10 | | x6FE | x5E9 | x539 | 32 | hZa\xFF |
| x21 | x4D | x47 | x0C | QMT476 | x6D8 | x5F3 | x52D | 64 | hlR\xBF |
| x21 | x36 | x47 | x0A | QRW813 | x6DF | x5F3 | x539 | 64 | hhF\xFF |
| x21 | x41 | x1E | x12 | SNG712 | x6EB | x5F0 | x526 | 64 | hjS\xFF |
| x10 | x800A | x41 | x08 | 'QMY687 ' | x6E6 | x5F1 | x53E | 16 | hZE? |
| x10 | x800C | x18 | x01 | 'QRR259 ' | x6E3 | x5F2 | x532 | 16 | h\E? |
| x10 | x8011 | x49 | x0E | 'W3U795 ' | x6D1 | x5F0 | x523 | 16 | hbF? |
| x10 | x8014 | x20 | x13 | 'W3R171 ' | x6CE | x5F5 | x527 | 16 | hd&lt;? |
| x10 | x8015 | x21 | x13 | 'W4A195 ' | x6DA | x5EE | x52A | 16 | h^D? |
| x10 | x1C | x3A | x12 | 'W4A820 ' | x6B9 | x5F6 | x511 | 16 | hR;? |
| x10 | x09 | x4D | x0B | 'W4C593 ' | x6E6 | x5F4 | x53C | 16 | haG? |
| x10 | x1D | x41 | x12 | 'W4R342 ' | x6E4 | x5F1 | x535 | 16 | hZJ? |
| x10 | x10 | x17 | x05 | 'WAA390 ' | x6E9 | x5F8 | x523 | 16 | hY=? |
| x10 | xDDC1 |xDDC1| x0D | ' ' | x703 | x5E9 | x535 | 32 | hNb\xFF |
| x10 | xDDC1 |xDDC1| x0F | ' ' | x70B | x5EF | x537 | 32 | hHX\xFF |
| x10 | xDDC1 |xDDC1| x10 | ' ' | x6FE | x5E9 | x539 | 32 | hZa\xFF |
| x21 | x4D | x47 | x0C | 'QMT476 ' | x6D8 | x5F3 | x52D | 64 | hlR\xBF |
| x21 | x36 | x47 | x0A | 'QRW813 ' | x6DF | x5F3 | x539 | 64 | hhF\xFF |
| x21 | x41 | x1E | x12 | 'SNG712 ' | x6EB | x5F0 | x526 | 64 | hjS\xFF |
</pre>
<hr>© 2020-2025 Renaud Fivet

View File

@@ -13,7 +13,7 @@ Getting started with a micro-controller usually means picking up a board,
an IDE, some RTOS or a set of libraries. Depending of your level of experience,
your budget and the solutions you select, the learning curve may be a steep
one and what you will learn could be very limited if you end up cornered in a
sandbox with no understanding of whats going on under the hood.
sandbox with no understanding of what's going on under the hood.
<p>
Commercial solutions and mature open source projects are a must if you want to
develop products with some level of quality. Unfortunately their complexity is
@@ -24,7 +24,7 @@ not addressing what you need to learn.
Starting from scratch, on the other hand, is not something often documented and
when it is, it is usually after the fact. So if you want to learn how to do it
you need to catch the opportunity to watch someone going through the steps and
explaining whats going on.
explaining what's going on.
<p>
I will try to capture here my own “STM32 bring up” journey using a step by step
approach, writing down the problems faced and decisions taken while evolving
@@ -62,7 +62,7 @@ for further evolution.
<h2><a id="part2">Part II: Let's talk!</a></h2>
Its time to move to a more talkative interface so that the board not
It's time to move to a more talkative interface so that the board not
only winks but also speaks. Again I will go through several steps to get
to a working interrupt driven asynchronous serial communication.
<ul>
@@ -117,8 +117,12 @@ during startup.
<li> Read a <a href="39_resistor.html">Resistor</a> Value.
</ul>
<h2>Appendices</h2>
<h2><a id="part4">Part IV: What You See Is What You Get!</a></h2>
<ul>
<li> Display temperature readings on a quad 7 segment LED display.
</ul>
<h2>Appendices</h2>
<ul>
<li> <a href="AA_factory.html">Factory-programmed</a> values.
</ul>