Assignment #4: USART Library

📚 Assignment 4 CMPE1250: USART Library

📋 Overview

In this ICA you will begin your library for USART. In the process of completing this assignment, you will:

  • Learn about and implement basic UART functions.
  • Create programs that use polling as a mechanism for detecting state changes in hardware.
  • Create non-blocking and blocking library functions.

1️⃣ Preparatory Work:

  • Create a new library for the UART, following the standard library creation procedure.

  • Update your GPIO library to include the function that configures the alternate function selection. This will be used to configure the GPIO pins for USART2.

2️⃣ Part A

You may use the following header content as a guide to what you need to include in your library. The implementation details are up to you, but some suggestions for each function are included below:

//******************
//UART Library
//
// CREATED: 11/05/2023, by Carlos Estay
//
// FILE: uart.h
//
#ifndef UART_H
#define UART_H

#include "stm32g031xx.h"

/// @brief 
/// @param  UartStructPtr
/// @param  BaudRate
/// @param  Interrupt 
void UART_Init(USART_TypeDef*, uint32_t, char);

/// @brief 
/// @param  UartStructPtr
/// @param  byte
void UART_TxByte(USART_TypeDef*, uint8_t);

/// @brief 
/// @param  string
void UART_TxStr(USART_TypeDef*, const char*);

/// @brief transmit a buffer of a given size
/// @param  uart
/// @param  buffer
/// @param  size
void UART_TxBuffer(USART_TypeDef*, uint8_t*, uint16_t);

/// @brief read a byte, non-blocking,
/// @param  pointer to a character
/// @return 1 if byte read, 0 if not
uint8_t UART_RxByte(USART_TypeDef* , uint8_t*); 

#endif /* UART_H */

3️⃣ Implementation Strategy

    //This assumes you have already Set pins TX and RX pins to the proper alternate function
    //Ensure that the port clock is turned on for GPIO    
    //Ensure that the peripheral clock is enabled for USART2 (RCC_APBENR1 (RM::5.4.15))

    void UART_Init(USART_TypeDef* pUart, uint32_t baud_rate, char int)
    {
        /*Some steps here might no necessarily be placed inside this function*/  
        //Turn on the transmitter and receiver for the USART (USART_CR1 (RM::33.8.1))
        //Set the BAUD rate for the UART, using 10x fixed point arithmetic conversion with the known bus rate and 
        //the desired BAUD rate in the calculation. (USART_BRR (RM::33.8.5))
        //Turn on the USART (USART_CR1 (RM::33.8.1)) (must be done after configuration) 
    }

    UART_TxByte(USART_TypeDef* pUart, uint8_t data)
    {
        //Wait for the TXFNF flag of USART_ISR to set (USART_ISR (RM::33.8.9)). 
        //Note: the TXFNF register name is odd in the derivative file!
        //Write the data to USART_TDR (USART_TDR (RM::33.8.13))
    }

    uint8_t UART_RxByte(USART_TypeDef* pUart , uint8_t* pData)
    {
        //If the RXFNE flag is set in USART_ISR, read USART_RDR and place the result at the target of the provided 
        //data pointer (pData). Return a value indicating that the data target is valid. Note: the RXFNE register 
        //name is odd in the derivative file! Otherwise, if the RXFNE flag is clear in USART_ISR, 
        // return a value indicating that the data target is not valid.
    }

    void UART_TxBuffer(USART_TypeDef* pUart, uint8_t* pData, uint16_t size)
    {
        //Transmits an array of "size" bytes starting from *pData
    }

    void UART_TxStr(USART_TypeDef* pUart, const char* pData)
    {
        //Transmits a string starting from *pData until the end of the string (null character)
    }

4️⃣ Testing

  • Create a standard project for testing your USART library, adding the necessary library files to the project.

  • In the one-time initializations section of your program, initialize USART2 at 38400 BAUD RATE, using the default boot clock speed of 16MHz.

  • Open up Putty or TeraTerm (or any terminal of your preference) and configure the terminal to use your serial port at 38400 BAUD. Your VCOM port might change from machine to machine, so check to make sure you are using the correct COM port by finding the port in device manager:

  • Initialize the user LED for use on PA5 using your GPIO library.

  • Initialize also PC10 as a GPIO output.

NOTE: Save the code from each part in separate conditional preprocessor blocks so that you may easily recall any part of the ICA without major code revision.

5️⃣ Implementations

Part A

  • In your main program loop, use your TxByte function to send a ‘.’ character to Terminal Application (i.e. TERA TERM) approximately every 200ms.

Part B

  • Add functionality to your code so that if a character is received during your main program loop, you show it in the debug terminal. Also have your code immediately send the character back to the Terminal Application so it will be visible in it (remote echo).

  • Remember to run your code in debug mode, or the debug terminal won’t be available. Remember also, that focus will need to be on the Terminal Application in order to send characters from it.

  • Add a test in your code to determine if the ORE bit in the USART_ISR register is set. If it is, display a message to the debug terminal that is suitable for what this flag represents (look it up!).

  • Run your code, and hit keys slowly in the Terminal Application, while watching it and the debug terminal.

  • In the Terminal Application, hit a bunch of keys quickly. What happens in the debug terminal?

Part C

  • If you implemented Part A using a blocking delay for 200[ms], how could that be changed so that the code is still responsive to received characters, but still maintains an approximate 200[ms] time between transmitted characters?

  • Toggle PC10 at the end of the infinite loop, and use a scope to observe the timing of the resultant waveform. This will describe the timing of your main loop, and therefore the responsiveness of your code to received characters.

  • To prevent buffer overrun, polling needs to be done at a high rate. In the future, we will find that interrupts effectively solve this problem.

  • Is it possible for you to have your buffer overrun now?, if not?

Part D

  • Modify the portion of the code that receives characters from the Terminal Application and echo them back. All alphabetic characters will be echoed back as uppercase, regardless of source case. Other characters will remain unaffected. All whitespace/unprintable characters will be filtered out as well.

  • Use no numeric literals in your code! Also, note the single bit difference between upper and lower case!