In this lab, you will be adding a communication interface to your driver library. The interface will utilize UART1 to transfer data between the STM32 and the linux host. Once you have the basic link sending and receiving characters, you will build on these primitives to allow the system to have access to standard C functions from the newlib library.
In this portion of the lab you will learn about configuring relevant I/O pins along with the UART module.
The STM32 has a very flexible I/O pin design. The I/O for a specific internal module like UART1 can be routed to specific pins on almost every port. The designer can decide which port is most appropriate given that some pin arrangements are mutually exclusive and prevent the use of the peripheral for other purposes. To designate the a pin is going to be dedicated to a specific module, the pin will be designated as "Alternate Function".
We will be concerned with two UART1 pins - TX (transmit) and RX (receive). PC4 (TX) and PC5 (RX) will be selected as the pins that we will use for UART1. The initialization will follow very closely to what was done for the LED driver in Lab1. However, notice that the pin is not defined as an input or an output but rather alternate function (GPIO_Mode_AF).
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOC,&GPIO_InitStructure);
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOC , &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOC,4,GPIO_AF_X);
GPIO_PinAFConfig(GPIOC,5,GPIO_AF_X);
The UART module is very flexible and capable. However, for the purposes much of the default configuration is adequate. We will primarily be concerned about setting the proper baud rate.
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
USART_StructInit(&USART_InitStructure);
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1 ,&USART_InitStructure);
USART_Cmd(USART1 , ENABLE);
Don't forget to add stm32f30x_usart.o to the "OBJS" variable in your Makefile.
Initially, we will develop functions to send and receive characters using polling to test the status of the receiver and the transmitter. In future labs, we will replace this approach with one that allows us to be more efficiently use the processor's cycles. For now, polling represents the simplest approach to getting initial functionality from the UART.
To transmit characters, we will need a routine to put characters on the transmitter. This routine will need to take a character as input, check to see if the transmitter is busy, and then write the character when the transmitter is available. The code to poll the UART status register and then write the data to the transmitter is as follows:
while (USART_GetFlagStatus(USART1,USART_FLAG_TXE) == (uint16_t)RESET);
USART_SendData(USART1, c);
Write a putchar function with the following prototype. For now, your putchar function can always return 0.
int putchar(int);
Similar to putchar, we also need a function to read characters from UART - getchar. This function will poll for the availability of a character, read it from the receiver, and the return it. The code to poll the UART's receiver is as follows:
while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == (uint16_t)RESET);
c = USART_ReceiveData(USART1);
Write a getchar function with the following prototype.
int getchar(void);
With the UART configured and our helper functions written, the USB-Serial adapter needs to be connected to the STM32. You are going to use jumper wires to connect the pins using the pin assignment below. The STM pins have very clear labels. However, the labels on the USB-Serial adapter are less clear but still legible at the bottom edge.
Regarding connecting the components, notice that the TX on the STM is connected to the RX on the USB-Serial adapter. Also, note that you will need to connect the ground of the USB-Serial Adapter to a ground pin on the STM.
STM32 Pin | USB-Serial Pin Label |
---|---|
PC4 | RX |
PC5 | TX |
GND | GND |
bhimebau@osprey:~$ ls /dev | grep ttyUSB
ttyUSB0
bhimebau@osprey:~$
bhimebau@osprey:~$ serialT
while(1) {
putchar('a');
}
putchar(getchar())
serialT
abcd
abcd
void putstring(char *);
Newlib is a port of standard C libraries that does not depend on an operating system. The library expects that the programmer will provide functions that know how to handle the services that the operating system typically provides. Even though our putstring() function is useful, sometimes it would be more helpful to have a more full-featured printf().
The library functions that need to be provided by the programmer are called "stubs". A good example of a template for the stub functions is posted at this site. We will adapt this piece of code to utilize our new getchar and putchar functions.
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);
We are going to be extending the sequenced led code from lab1. The lab2 version will allow you to pause the code from serialT using ‘p'=pause, ‘r'=resume (any other keystroke can be ignored). Your code should still allow the user to pause the sequence using the user button. Additionally, when paused your code should indicate the current led by printing it to the console. It should only print one time for each pause event. There are compass directions printed near the leds on the board (N, E, S, W). Use the compass directions when you are indicating which led. Use (NE, SE, SW, NW) for the other leds. Additionally, use ALL and NONE for the corresponding states.
This assignment is due by midnight on 1/24. At midnight, your AI will pull the current state of your repository to review your code. In the following lab session, you will be asked to demonstrate your solution. Independently, you will also write a lab report describing in approximately 300 words or less the following:
You will turn in this lab report in the oncourse assignments section.