by using the arrow operator, which will dereference the pointer to the struc- ture and access the value of the member. For example, setting the USART1 data register (DR) to 54 hexadecimal would look like this:
U SART − > DR = 0x54
One can use the bit definitions instead of the cryptic and harder to main- tain way of setting bits by left shifting. Below is an example setting the USART Enable bit in USART Control Register 1. One can easily determine which method is more readable.
Left shifting:
U SART 1 − > CR1 | = (1 << 13) Bit definition:
U SART 1 − > CR1 | = U SART _CR1_U E One can also use the “set bit” macro provided in the same file:
SET _BIT (U SART 1 − > CR1, U SART _CR1_U E)
4.3
Microcontroller
4.3.1
Debugging
When debugging on STM32, it is important to properly set how I2C, watch-
dog, timers and more, should behave. If the watchdog is enabled when
debugging it will most likely time out and reset the system when hitting a breakpoint. This is in most cases unwanted behavior and interrupts the de- bugging process. The I2C bus can timeout when hitting a breakpoint and so on. It is possible to set how some microcontroller peripherals should behave when hitting a breakpoint. If using a watchdog or timer one can set it to stop counting when at a breakpoint, if wanted. This will avoid the debug- ging process to be the cause of the watchdog time out. More on this can be found in the specific STM32 microcontroller reference manual under debug support.
Using the debugger
The debugger makes it possible to monitor the programs flow of execution and watch values of variables and registers at run-time. This helps locating and
remove logical errors from the program. When debugging it is possible to halt the processor at all executable lines of code, giving full control of execution. Breakpoints are used to mark which line of code one wants to investigate closer. It is possible to use one or more breakpoints. If a line with non- executable code is selected, for instance a comment, the next executable line is selected automatically instead. After inserting breakpoints, the debugger can be run. There are usually five commands to control the flow of execution: 1. Step: This command steps to the next executable line of code. If the next line is a function call, one will be taken to the first line in the function.
2. Step Over: This command acts like a step as long as the next line is not a function call. If the next line is a function call, it will run past all the code in that function.
3. Step Out: This command executes the rest of the code in a func- tion then continues debugging the next executable line in the function caller’s code.
4. Run to Cursor Line / Continue: This command executes the code until the next breakpoint is reached.
5. Stop: Stops the debugging.
4.3.2
Interrupts
An interrupt signals an internal or external event in a microcontroller that requires handling. An interrupt will disrupt the flow of execution. Handling is done in Interrupt Service Routines (ISR) and for USART1 an ISR can look
like in figure4.3:
It is necessary to check the USART 1 interrupt status flags to determine why the interrupt handler have been called, as all USART 1 interrupts will call the same handler. This handler simply checks if a USART receive inter- rupt have been received and if so, data is pushed to a queue and the USART receive interrupt is cleared.
4.3.3
printf()
The printf() function provided by the C standard library, defined in the stdio.h header file is the standard way of printing text when programming in the C language. When printing on, e.g., the Windows operating system, the standard output stream is set by the operating system.
4.3. MICROCONTROLLER 51
Figure 4.3: ISR code example. Retarget printf() to UART
When working on an embedded system without an operating system, like an ARM microcontroller, there is no standard input or output stream. This means one have to implement some low level code usually provided by the operating system. This is called retargeting and often it is retargeted to UART or some other communication bus. In CooCox IDE one can include the newlib syscalls.c file which contains mostly empty function definitions that have to be implemented. The _write() and _read() functions are used by the stdio.h header file for input and output of data. To be able to use printf() one would have to implement _write() and to use scanf() one would have to implement _read(). Only the _write() function has been implemented in this thesis. It was desired to retarget the printf() function to UART and to be able to do so one would have to send one and one byte over UART until all data provided to printf() has been sent. How this was done can be seen in the syscalls.c file in the microcontroller appendix.
Use printf() with floating point numbers in CooCox
By default, it is not possible to use the printf() function to output floating point numbers in a CooCox project to this date, so a work-around is needed. This can be done in three steps:
1. Enable the use of math.h.
2. In the startup code in startup_stm32f10x_hd.c the line: (void*)&pulStack[ST ACK_SIZE − 1] has to be replaced with:
(void(*)(void))((unsignedlong)pulStack + sizeof (pulStack)), This is because the stack must be double-word (64-bit) aligned (ARM, 2012, p. 17), hence the cast to unsigned long which will ensure that the stack is accessed properly.
3. Increase the stack size from the standard 1 KB to 16 KB by changing the line:
#def ine ST ACK_SIZE 0x00000100
to
#def ine ST ACK_SIZE 0x00001000
this must most likely be done to be able to compile, because of the bigger memory footprint needed to include the full printf() implemen- tation.
4.3.4
Using standard library math.h in CooCox
To be able to use the functions declared in the C standard library math.h header file with CooCox, one have to link to the library ’m’. This can be done by simply adding the letter ’m’ in the project configuration under linked libraries.