mirror of
https://github.com/rfivet/stm32bringup.git
synced 2024-12-18 23:06:28 -05:00
161 lines
4.9 KiB
HTML
161 lines
4.9 KiB
HTML
|
<!DOCTYPE html>
|
|||
|
<html lang="en">
|
|||
|
<head>
|
|||
|
<meta charset="UTF-8">
|
|||
|
<title>2.3 Hello There!</title>
|
|||
|
<link type="text/css" rel="stylesheet" href="style.css">
|
|||
|
</head>
|
|||
|
<body>
|
|||
|
<h1>2.3 Hello There!</h1>
|
|||
|
|
|||
|
Looking for a <i>“you had me at hello”</i> moment? Let’s see how serial
|
|||
|
transmission works for you.
|
|||
|
|
|||
|
<h2>Implementation</h2>
|
|||
|
|
|||
|
I make a copy of <b>board.c</b> into <b>usart1tx.c</b> to add support for the
|
|||
|
USART1 peripheral.
|
|||
|
<p>
|
|||
|
In order to make a first transmission, the peripherals have to be
|
|||
|
initialized. As the TX/RX of USART1 are mapped on pin PA9 and PA10, I
|
|||
|
need to configure GPIOA first.
|
|||
|
<ul>
|
|||
|
<li> GPIOA needs to be enabled via RCC AHB Enable Register as GPIOs are on
|
|||
|
AHB bus.
|
|||
|
|
|||
|
<li> PA9 and PA10 set to alternate mode.
|
|||
|
|
|||
|
<li> Alternate function USART1 selected for PA9 and PA10.
|
|||
|
</ul>
|
|||
|
Then USART1 can be configured:
|
|||
|
<ul>
|
|||
|
<li> USART1 enabled via RCC APB2 Enable Register as USARTs are on the APB
|
|||
|
bus.
|
|||
|
|
|||
|
<li> Baud rate set to 9600 bauds.
|
|||
|
|
|||
|
<li> USART itself and transmission needs to be enabled via the Control
|
|||
|
Register (CR1).
|
|||
|
</ul>
|
|||
|
By default the transmission format is 8N1: 8 bit data, no parity and 1
|
|||
|
stop bit.
|
|||
|
|
|||
|
<pre>
|
|||
|
/* USART1 9600 8N1 */
|
|||
|
RCC_AHBENR |= RCC_AHBENR_IOP( A) ; /* Enable GPIOA periph */
|
|||
|
GPIOA[ MODER] |= 0x0A << (9 * 2) ; /* PA9-10 ALT 10, over default 00 */
|
|||
|
GPIOA[ AFRH] |= 0x110 ; /* PA9-10 AF1 0001, over default 0000 */
|
|||
|
RCC_APB2ENR |= RCC_APB2ENR_USART1EN ;
|
|||
|
USART1[ BRR] = 8000000 / 9600 ; /* PCLK [8MHz] */
|
|||
|
USART1[ CR1] |= USART_CR1_UE | USART_CR1_TE ; /* Enable USART & Tx */
|
|||
|
</pre>
|
|||
|
|
|||
|
Sending data is done by writing in the Transmission Data Register (<b>TDR</b>).
|
|||
|
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
|
|||
|
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.
|
|||
|
|
|||
|
<pre>
|
|||
|
void kputc( unsigned char c) {
|
|||
|
static unsigned char lastc ;
|
|||
|
|
|||
|
if( c == '\n' && lastc != '\r')
|
|||
|
kputc( '\r') ;
|
|||
|
|
|||
|
/* Active wait while transmit register is full */
|
|||
|
while( (USART1[ ISR] & USART_ISR_TXE) == 0) ;
|
|||
|
|
|||
|
USART1[ TDR] = c ;
|
|||
|
lastc = c ;
|
|||
|
}
|
|||
|
</pre>
|
|||
|
|
|||
|
The high level C function I need for this simple test is <code>puts()</code>.
|
|||
|
I make my own implementation but I keep the same declaration as the standard
|
|||
|
header that come with the C compiler.
|
|||
|
|
|||
|
<pre>
|
|||
|
int puts( const char *s) {
|
|||
|
while( *s)
|
|||
|
kputc( *s++) ;
|
|||
|
|
|||
|
kputc( '\n') ;
|
|||
|
return 0 ;
|
|||
|
}
|
|||
|
</pre>
|
|||
|
|
|||
|
Finally I use a standard C implementation for <b>hello.c</b>.
|
|||
|
|
|||
|
<pre>
|
|||
|
/* hello.c -- hello there */
|
|||
|
#include <stdio.h>
|
|||
|
#include <stdlib.h>
|
|||
|
|
|||
|
int main( void) {
|
|||
|
puts( "hello, world") ;
|
|||
|
return EXIT_SUCCESS ;
|
|||
|
}
|
|||
|
</pre>
|
|||
|
|
|||
|
<h2>Build</h2>
|
|||
|
|
|||
|
To build I update the software composition in <b>Makefile</b> by adding a new
|
|||
|
<code>SRCS</code> line.
|
|||
|
|
|||
|
<pre>SRCS = startup.c usart1tx.c hello.c</pre>
|
|||
|
|
|||
|
Calling make, I can see that there is now some variable in <b>BSS</b> section
|
|||
|
of the RAM. It is <code>lastchar</code> local to <code>kputc()</code>. Because
|
|||
|
of word alignment <code>BSS</code> occupies 4 bytes.
|
|||
|
|
|||
|
<pre>
|
|||
|
$ make
|
|||
|
f030f4.elf
|
|||
|
text data bss dec hex filename
|
|||
|
413 0 4 417 1a1 f030f4.elf
|
|||
|
f030f4.hex
|
|||
|
f030f4.bin
|
|||
|
</pre>
|
|||
|
|
|||
|
<h2>Testing</h2>
|
|||
|
|
|||
|
After flashing the board with the new executable, I place back the
|
|||
|
<b>BOOT0</b> jumper and press the reset button, the board user LED blinks
|
|||
|
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.
|
|||
|
<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
|
|||
|
ports. If I try to open it with Arduino IDE, I get an error message as I
|
|||
|
need to belong to <b>dialout</b> group to open that TTY for reading and
|
|||
|
writing.
|
|||
|
|
|||
|
<pre>sudo usermod -a -G dialout $USER</pre>
|
|||
|
|
|||
|
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.
|
|||
|
|
|||
|
<h2>Checkpoint</h2>
|
|||
|
|
|||
|
I have now a functional serial transmission channel through <b>USART1</b>. I
|
|||
|
have only a first implementation for <code>puts()</code>, but I will add
|
|||
|
support for other stdio functions when needed.
|
|||
|
<p>
|
|||
|
<a href="24_stm32flash.html">Next</a>, I will switch to an open source tool
|
|||
|
for flashing over serial connection that works on both Windows and Linux.
|
|||
|
|
|||
|
<hr>© 2020-2024 Renaud Fivet
|
|||
|
</body>
|
|||
|
</html>
|