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:
@@ -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>Toolchain’s 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>
|
||||
|
@@ -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, let’s 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 let’s 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( ;;) ;
|
||||
|
@@ -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. It’s 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.
|
||||
|
@@ -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 that’s 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.
|
||||
|
@@ -8,12 +8,12 @@
|
||||
<body>
|
||||
<h1>1.6 The Tick</h1>
|
||||
|
||||
<img alt="It’s blue! It blinks! It’s 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> It’s 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>
|
||||
|
||||
It’s 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, it’s 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 didn’t 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.
|
||||
|
@@ -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 doesn’t have global scope, but I can
|
||||
guess it’s 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>
|
||||
|
@@ -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
|
||||
didn’t introduce any <del>bugs</del> changes, just code overhead.
|
||||
didn't introduce any <del>bugs</del> changes, just code overhead.
|
||||
|
||||
<h2>Checkpoint</h2>
|
||||
|
||||
|
@@ -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
|
||||
(that’s the S in USART), asynchronous communication (that’s the A) which
|
||||
(that's the S in USART), asynchronous communication (that’s 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 doesn’t 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
|
||||
|
@@ -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 doesn’t have a user
|
||||
is undefined, the code would be removed for a board that doesn't have a user
|
||||
LED.
|
||||
|
||||
<pre>
|
||||
|
@@ -8,7 +8,7 @@
|
||||
<body>
|
||||
<h1>2.3 Hello There!</h1>
|
||||
|
||||
Looking for a <i>“you had me at hello”</i> moment? Let’s see how serial
|
||||
Looking for a <i>“you had me at hello”</i> moment? 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 it’s functional and
|
||||
that’s 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>
|
||||
|
||||
|
@@ -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 doesn’t 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 won’t 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
|
||||
|
@@ -8,7 +8,7 @@
|
||||
<body>
|
||||
<h1>2.6 uptime</h1>
|
||||
|
||||
It’s 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>,
|
||||
it’s <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 doesn’t
|
||||
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 won’t
|
||||
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 haven’t 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 it’s 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. It’s 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 didn’t 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.
|
||||
|
@@ -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>. It’s
|
||||
<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>
|
||||
What’s 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 it’s not
|
||||
Library modules are implicitly part of the composition, so it's not
|
||||
necessary to list them anymore.
|
||||
|
||||
<pre>
|
||||
|
@@ -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>
|
||||
|
||||
Let’s 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, 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 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 isn’t 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 didn’t 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, it’s
|
||||
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.
|
||||
It’s 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.
|
||||
|
@@ -8,7 +8,7 @@
|
||||
<body>
|
||||
<h1>2.9 Interrupt Driven Transmission</h1>
|
||||
|
||||
It’s 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 don’t 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, it’s 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, it’s 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.
|
||||
|
@@ -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 it’s 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 didn’t 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 don’t 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 don’t 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 don’t 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 what’s
|
||||
The humidity value seems off the mark. So I need to investigate what's
|
||||
the issue.
|
||||
|
||||
<h2>Checkpoint</h2>
|
||||
|
@@ -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 didn’t 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 doesn’t 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
|
||||
it’s 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>
|
||||
|
||||
It’s 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 didn’t 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 didn’t 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
|
||||
|
@@ -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 won’t use
|
||||
Parasitic Power Mode if a two wire only interface is needed. I won't use
|
||||
this feature for now.
|
||||
|
||||
<h2>Communication protocol</h2>
|
||||
|
@@ -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
|
||||
couldn’t 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 it’s 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
|
||||
|
@@ -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℃. That’s 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 don’t 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 it’s 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
|
||||
|
@@ -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 don’t 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.
|
||||
|
@@ -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 don’t 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>
|
||||
Let’s 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> doesn’t use interrupt routines.
|
||||
<b>blink</b> doesn't use interrupt routines.
|
||||
|
||||
<h2>ISR Vector in RAM</h2>
|
||||
|
||||
|
@@ -8,7 +8,7 @@
|
||||
<body>
|
||||
<h1>3.9 Reading a Resistor Value</h1>
|
||||
|
||||
I used the ADC previously to read the internal sensors, so it’s 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>
|
||||
<b><i>VDDA</i> * ADCraw / 4095 = <i>VDDA</i> * Rref / (Rref + Rmeasured)</b>
|
||||
<p>which can be further simplified as<br>
|
||||
<b>ADCraw * Rmeasured = Rref * (4095 – ADCraw)</b>
|
||||
<b>ADCraw * Rmeasured = Rref * (4095 - ADCraw)</b>
|
||||
<p>The resistor value is then given by<br>
|
||||
<b>Rmeasured = Rref * (4095 – ADCraw) / ADCraw</b><br>
|
||||
<b>Rmeasured = Rref * (4095 - ADCraw) / ADCraw</b><br>
|
||||
or<br>
|
||||
<b>Rmeasured = Rref * (4095 / ADCraw – 1)</b>
|
||||
<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>
|
||||
|
@@ -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<? |
|
||||
| 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<? |
|
||||
| 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
|
||||
|
@@ -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 what’s 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 what’s 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>
|
||||
|
||||
It’s 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>
|
||||
|
Reference in New Issue
Block a user