I am new here, first post, so thanks in advance for being gentle with me 🙂
After spending weeks trying to make this work and searching examples/education/forum, i now reach out and hope someone is willing to help.
Goal:
Write simple program for an STM32G030K8 MCU for basic UART functionality. Transmit one char from PC, receive a hard-coded char from MCU.
The issue:
After sending a char, i do not receive any chars in return. Using hercules terminal tool and serial adapter.
The hardware (wiring, defects etc.) to transmit from MCU is verified, since i wrote a simple HAL-based program to transmit with success through ST Cube IDE. Therefore, i strongly suspect that the code is the issue. Also, i have no experience with debugging (i am a beginner programmer), so that is currently not an option.
PS. Using uKeil IDE and ST-LINK v2 programmer, c99.
#include "stm32g0xx.h"
void initClocks(void){
//RCC->AHB2ENR |= RCC_AHB2ENR_GPIOAEN; // ENABLE GPIO PORT A CLOCK (BIT 0) ??? (I believe the next line replaces this one)
RCC->IOPENR |= (1<<0); // Enable GPIOA Clock MCO
RCC->APBENR2 |= RCC_APBENR2_USART1EN; // ENABLE UART1 CLOCK (BIT 14) ok
}
void configPinMode(void){
// RESET PIN MODES
GPIOA->MODER &= ~((3u << 18) // CLEAR PA9 ok
|(3u << 20)); // CLEAR PA10 ok
// SET PIN MODES
GPIOA->MODER |= ((2u << 18) // SET PA9 TO AF ok
|(2u << 20)); // SET PA10 TO AF ok
}
void setAF(void){
// RESET ALTERNATE FUNCTION. AFR[1] IS THE
// ALTERNATE FUNCTION HIGH REGISTER
GPIOA->AFR[1] &= ~((15u << 4) // CLEAR PA9 AF ok
|(15u << 8)); // CLEAR PA10 AF ok
// SET ALTERNATE FUNCTION
GPIOA->AFR[1] |= ((1u << 4) // SET PA9 AF not sure if position (high/low) register is ok (maybe AFR[1] is high and AFR[0] is low)
|(1u << 8)); // SET PA10 AF not sure if position (high/low) register is ok (maybe AFR[1] is high and AFR[0] is low)
}
void configUart1Pins(void){
// SET PIN MODE TO ALTERNATE FUNCTION
configPinMode();
// SET ALTERNATE FUNCTION TO BE UART1
setAF();
}
void configUart1(void){
// CONFIGURE USART1 CR1 REGISTER
// CLEAR BITS
USART1->CR1 &= ~(USART_CR1_M1 // CLEAR M1 FOR 1 START BIT AND 8 DATA BITS (28) ok
|(0x03 << 26) // INHIBIT INTERRUPTS AT BITS 26 AND 27 (27/26) ok
|USART_CR1_OVER8 // OVERSAMPLING BY 16 (15) ok
|USART_CR1_CMIE // INHIBIT CHARACTER MATCH INTERRUPT (14) ok
|USART_CR1_MME // DON'T ENABLE MUTE MODE (13) ok
|USART_CR1_M0 // CLEAR M0 FOR 1 START BIT AND 8 DATA BITS (12) ok
|USART_CR1_PCE // NOT IMPLEMENTING PARITY CONTROL (10) ok
|(0x1F << 3) // INHIBIT INTERRUPTS AT BITS 4 TO 8 (4-8) ok
|USART_CR1_TE // DON'T ENABLE TRANSMITTER JUST YET (3) ok
|USART_CR1_RE // DON'T ENABLE RECEIVER JUST YET (2) ok
|USART_CR1_UE); // DON'T ENABLE UART1 JUST YET (0) ok
// CONFIGURE USART CR2 REGISTER
// CLEAR BITS
USART1->CR2 &= ~(USART_CR2_RTOEN // DISABLE RECEIVER TIMEOUT (23) ok
|USART_CR2_ABREN // NO AUTOMATIC BAUD RATE DETECTION (20) ok
|USART_CR2_MSBFIRST // TRANSMIT/RECEIVE LSB FIRST (19) ok
|(0x03 << 16) // IDLE STATE HIGH FOR RX/TX PINS (17/16) ok
|USART_CR2_SWAP // DON'T SWAP FUNCTION OF RX/TX PINS (15) ok
|USART_CR2_LINEN // NO LIN MODE (14) ok
|(0x03 << 12) // 1 STOP BIT (13/12) ok
|USART_CR2_CLKEN // DON'T USE CLOCK WITH UART (11) ok
|USART_CR2_LBDIE); // NO LIN BREAK DETECTION INTERRUPT (6) ok
// CONFIGURE USART CR3 REGISTER
// CLEAR BITS
USART1->CR3 &= ~(USART_CR3_TCBGTIE // NO TRANSMISSION COMPLETE BEFORE GUARD TIME INTERRUPT (24) ok
|USART_CR3_DEM // NO DRIVER ENABLE MODE (14) ok
|(0x7F << 3) // DISABLE VARIOUS IRRELEVANT MODES (9-3) ok
|USART_CR3_IREN // NO IrDA MODE (1) ok
|USART_CR3_EIE); // INHIBIT ERROR INTERRUPT (0) ok
// SET BITS
USART1->CR3 |= (USART_CR3_OVRDIS // DISABLE OVERRUN FUNCTIONALITY (12) ok
|USART_CR3_ONEBIT); // USE ONE SAMPLE BIT METHOD (11) ok
// SET BAUD RATE IN BRR REGISTER
USART1->BRR |= (138<<4); // Baudrate: Whole Number Part 16MHz/115200=138.8889 (Baudrate 115200) MCO
USART1->BRR |= (14<<0); // Baudrate: Fractional Part 0.8889*16=14.2224=14 (Oversampling 16) MCO
// ENABLE UART
USART1->CR1 |= (USART_CR1_TE // ENABLE TRANSMITTER (3) ok
|USART_CR1_RE // ENABLE RECEIVER (2) ok
|USART_CR1_UE); // ENABLE UART1 (0) ok
}
void initUART(void){
// INITIALISE REQUIRED CLOCKS. MUST ALWAYS BE DONE FIRST
// AS WITHOUT ENABLING THE CLOCKS THE PERIPHERALS CANNOT
// BE CONFIGURED OR USED.
initClocks();
// CONFIGURE PINS FOR UART1
configUart1Pins();
// CONFIGURE UART1
configUart1();
}
void transmitUart(uint8_t data){ // BYTE OF DATA TO BE TRANSMITTED
// WAIT UNTIL TRANSMIT DATA REGISTER IS READY TO TAKE DATA
// USART_ISR_TXE EXPANDS TO (1 << 7);
while(!(USART1->ISR & (1<<7))); // USART_ISR_TXE is not known, therefore bitmask is used instead
// LOAD DATA TO TRANSMIT REGISTER
USART1->TDR = data;
}
void transmitStrUart(char* str) // POINTER TO A STRING TO BE TRANSMITTED
{
// WHILE NOT END OF STRING
while(*str){
// TRANSMIT CHARACTER THEN INCREMENT POINTER TO NEXT CHARACTER
transmitUart(*str++);
}
}
uint8_t receiveUart(void){
uint8_t rxData = 0;
// IF THERE IS DATA IN THE RECEIVE DATA REGISTER
// USART_ISR_RXNE EXPANDS TO (1 << 5)
if(USART1->ISR & (1<<5)){ // USART_ISR_RXNE is not known, therefore bitmask is used instead
// READ DATA FROM THE REGISTER
rxData = USART1->RDR;
}
return rxData;
}
int main(void){
//SET UP UART
initUART();
while(1){
// IF DATA WAS RECEIVED
if(receiveUart() > 0){
//transmitStrUart("Character Receivednr");
// TRANSMIT AN ARBITRARY 'U' (ASCII 85) OVER UART
transmitUart(85);
}
}
}
Above code is strongly inspired by an example found online (hence the “ok” comments and alike).
Thanks in advance for your advice and help.
4