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>
|