1
0
mirror of https://github.com/rfivet/stm32bringup.git synced 2024-12-18 23:06:28 -05:00
stm32bringup/docs/23_hello.html

161 lines
4.9 KiB
HTML
Raw Normal View History

<!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?&nbsp; Lets 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 its functional and
thats 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 &lt;stdio.h>
#include &lt;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>