USART Configuration with Registers doesn't Work - c

I am trying to implement a driver for USART for my board(F746G-Disco). For now, I implement:
#include "UART_DRIVER.h"
#include "stm32f746xx.h"
#include "stm32f7xx_hal.h"
#include "stdint.h"
void uart_gpio_pin_init(void) {
__HAL_RCC_GPIOA_CLK_ENABLE();
// PA9 FOR USART1 TX AND PB7 FOR USART1 RX
GPIOA->MODER |= (2U << 18); // ALTERNATE FUNCTION
GPIOA->OTYPER |= (1U << 9);
GPIOA->OSPEEDR |= (1U << 19);
GPIOA->PUPDR |= (1U << 19);
GPIOA->AFR[1] |= (7U << 4); // AF7
__HAL_RCC_GPIOB_CLK_ENABLE();
GPIOB->MODER |= (2U << 6);
GPIOB->OTYPER |= (1U << 7);
GPIOB->OSPEEDR |= (1U << 17);
GPIOB->PUPDR |= (1U << 17);
GPIOB->AFR[0] |= (7U << 28); // AF7
}
void uart_init(void) {
uart_gpio_pin_init();
// disable USART
USART1->CR1 = 0x00; // Disable Uart => UE=0
USART1->CR1 &= (~(1U << 28) | ~(1 << 12)); // WORD LENGTH 8-BIT
USART1->CR1 &= ~(1U << 15); // 16BIT OVERSAMPLING
USART1->CR1 &= ~(1U << 10); // PARITY BIT DISABLE
USART1->CR1 |= (1U << 3); // USART1 TRASNMITTER MODE
USART1->CR1 |= (1U << 2); // USART1 RECEIVER MODE
// 115200kpbs BAUD-RATE, SYSTEMCLOCK:168 MHz
USART1->BRR = (0x5B2);
// ENABLE USART1
USART1->CR1 = 0x01;
}
void uart_transmit_data(const char *data) {
for (int var = 0; data[var] != '\0'; ++var) {
USART1->TDR = (uint32_t)data[var];
while((USART1->ISR & USART_ISR_TXE) == 0);
}
}
But the problem is that the value of USART1->CR1 does not change. In the manual, it is said that to have a writable bits, Uart Enable(UE) pin must be 0. I have already did that but still nothing change.
reference manual
datasheet(look page 76 for alternate function mapping)
Solution Edit:
I have solved the problem. The problem is I didn't enable the clock for USART. Once __HAL_RCC_USART1_CLK_ENABLE(); macro is invoked in uart_gpio_pin_init function just before the register adjustments of USART, we get rid of the problem!

The part
// ENABLE USART1
USART1->CR1 = 0x01;
will cancel the bits set in
USART1->CR1 |= (1U << 3); // USART1 TRASNMITTER MODE
USART1->CR1 |= (1U << 2); // USART1 RECEIVER MODE
You may want to use OR instead of simple assignment:
// ENABLE USART1
USART1->CR1 |= 0x01;

The problem is in the code that the USART clock wasn't enabled. Once __HAL_RCC_USART1_CLK_ENABLE(); macro is invoked in uart_gpio_pin_init function just before the register adjustments of USART, we get rid of the problem!

Related

IRQHandler variable

I wrote interrupt handler code here. The purpose of my code is to interrupt when I press the button. However, there is a problem. When the button is pressed, it interrupts and enters the handler, but does not increase the Buttonpress. I see the debugger reads buttonpress++, but after exiting the handler, the code freezes when it comes to the switch. Buttonpress = 1 does not happen. What is the reason of this? Do I need to assign the variable differently when assigning it?
Here is my Code :
/* 1 sec is 1600000 */
void delay(volatile uint32_t);
uint32_t ButtonPress = 0;
/* Interrupt Handlers */
void EXTI0_1_IRQHandler(void){
ButtonPress++;
EXTI->RPR1 |= (1U << 1);
}
int main(void) {
uint32_t ButtonPress = 0;
/* Enable GPIOA clock */
RCC->IOPENR |= (1U << 0);
/* Setup PA0 as output */
GPIOA->MODER &= ~(3U << 2*0);
GPIOA->MODER |= (1U << 2*0);
/* Setup PA1 as input */
GPIOA->MODER &= ~(3U << 2*1);
GPIOA->MODER |= (0U << 2*1);
/* External interrupt at PA1 port */
EXTI->EXTICR[0] |= (0U << 8*1);
/* Mask and Rising on Px1 */
EXTI->IMR1 |= (1U << 1);
EXTI->RTSR1 |= (1U << 1);
EXTI->FTSR1 |= (1U << 1);
/* Setup NVIC */
NVIC_SetPriority(EXTI0_1_IRQn, 0);
NVIC_EnableIRQ(EXTI0_1_IRQn);
while(1) {
switch(ButtonPress){
case 0:
/* Turn off LED */
GPIOA->ODR = (0U << 0);
break;
case 1:
/* Turn on LED 2sec interval */
GPIOA->ODR |= (1U << 0);
delay(3200000);
GPIOA->ODR ^= (1U << 0);
delay(3200000);
break;
case 2:
/* Turn on LED 1sec interval */
GPIOA->ODR |= (1U << 0);
delay(1600000);
GPIOA->ODR ^= (1U << 0);
delay(1600000);
break;
case 3:
/* Turn on LED 0.5sec interval */
GPIOA->ODR |= (1U << 0);
delay(800000);
GPIOA->ODR ^= (1U << 0);
delay(800000);
break;
case 4:
/* Turn on LED 0.1sec interval */
GPIOA->ODR |= (1U << 0);
delay(160000);
GPIOA->ODR ^= (1U << 0);
delay(160000);
break;
case 5:
/* Turn on LED */
GPIOA->ODR |= (1U << 0);
break;
case 6:
/* Button Clear */
ButtonPress = 0;
break;
}
}
return 0;
}
void delay(volatile uint32_t s) {
for(; s>0; s--);
}
`
I wrote interrupt handler code here. The purpose of my code is to interrupt when I press the button. However, there is a problem. When the button is pressed, it interrupts and enters the handler, but does not increase the Buttonpress. I see the debugger reads buttonpress++, but after exiting the handler, the code freezes when it comes to the switch. Buttonpress = 1 does not happen. What is the reason of this? Do I need to assign the variable differently when assigning it?
You have declared the ButtonPress variable twice: once in the global scope and once in main. When the interrupt is called, only the global scope version is in scope and therefore that variable is incremented. When it comes to the switch statement in main however, the other variable is in (a smaller) scope and so that variable is used instead. To fix this, you could remove the declaration of ButtonPress at the beginning of main.

USART3 Initilization STM32F103RB

I'm a beginner when it comes to using STM chips, and I have a project where I have to use all three USART terminals in Uvision.
I am using an STM32F103RB chip, and I already got the first two USART_init functions working, but I can't get the third one to work for some reason. I would really appreciate any help
Here are my USART_init functions:
/*----------------------------------------------------------------------------
Initialize UART pins, Baudrate
*----------------------------------------------------------------------------*/
void USART1_Init (void) {
int i;
RCC->APB2ENR |= ( 1UL << 0); /* enable clock Alternate Function */
AFIO->MAPR &= ~( 1UL << 2); /* clear USART1 remap */
RCC->APB2ENR |= ( 1UL << 2); /* enable GPIOA clock */
GPIOA->CRH &= ~(0xFFUL << 4); /* clear PA9, PA10 */
GPIOA->CRH |= (0x0BUL << 4); /* USART1 Tx (PA9) output push-pull */
GPIOA->CRH |= (0x04UL << 8); /* USART1 Rx (PA10) input floating */
RCC->APB2ENR |= ( 1UL << 14); /* enable USART#1 clock */
USART1->BRR = 0x0271; /* 115200 baud # PCLK2 72MHz */
USART1->CR1 = (( 1UL << 2) | /* enable RX */
( 1UL << 3) | /* enable TX */
( 0UL << 12) ); /* 1 start bit, 8 data bits */
USART1->CR2 = 0x0000; /* 1 stop bit */
USART1->CR3 = 0x0000; /* no flow control */
for (i = 0; i < 0x1000; i++) __NOP(); /* avoid unwanted output */
USART1->CR1 |= (( 1UL << 13) ); /* enable USART */
}
/*----------------------------------------------------------------------------
Initialize UART2 pins, Baudrate
*----------------------------------------------------------------------------*/
void USART2_Init (void) {
RCC->APB2ENR |= 1; // enable clock for AF
AFIO->MAPR |= 1<<3; // set USART2 remap
RCC->APB2ENR |= 1<<5; // enable clock for GPIOD
GPIOD->CRL &= ~(0xFF << 20); // Clear PD5, PD6
GPIOD->CRL |= (0x0B << 20); // USART2 Tx (PD5) output push-pull
GPIOD->CRL |= (0x04 << 24); // USART2 Rx (PD6) input floating
RCC->APB1ENR |= 1<<17; // enable clock for USART2
USART2->BRR = 0x138; // set baudrate -115.2kB from 36MHz
USART2->CR1 &= ~(1<<12); // force 8 data bits
USART2->CR2 &= ~(3<<12); // force 1 stop bit
USART2->CR3 &= ~(3<<8); // force no flow control
USART2->CR1 &= ~(3<<9); // force no parity
USART2->CR1 |= 3<<2; // RX, TX enable
USART2->CR1 |= 1<<5; // Rx interrupts if required
NVIC->ISER[1] = (1 << 6); // enable interrupts if required
USART2->CR1 |= 1<<13; // USART enable
}
/*----------------------------------------------------------------------------
Initialize UART3 pins, Baudrate
*----------------------------------------------------------------------------*/
void USART3_Init (void) {
RCC->APB2ENR |= 1; // enable clock for AF
AFIO->MAPR |= 1<<3; // set USART3 remap
RCC->APB2ENR |= 1<<4; // enable clock for GPIOC
GPIOC->CRH &= ~(0xFFUL << 4); /* clear PC10, PC11 */
GPIOC->CRH |= (0x04UL << 8); /* USART3 Rx (PC10) input floating */
GPIOC->CRH |= (0x01UL << 8); /* USART3 Tx (PC11) output push-pull */
RCC->APB1ENR |= 1<<20; // enable clock for USART3
USART3->BRR = 0x138; // set baudrate -115.2kB from 36MHz; USART3
//should have the same baudrate as USART2
USART3->CR1 &= ~(1<<12); // force 8 data bits
USART3->CR2 &= ~(3<<12); // force 1 stop bit
USART3->CR3 &= ~(3<<8); // force no flow control
USART3->CR1 &= ~(3<<9); // force no parity
USART3->CR1 |= 3<<2; // RX, TX enable
USART3->CR1 |= 1<<5; // Rx interrupts if required
NVIC->ISER[1] = (1 << 6); // enable interrupts if required
USART3->CR1 |= 1<<13; // USART enable
}
Your first line for the USART3 initialization is wrong :-)
RCC->APB2ENR |= 1; // enable clock for AF
must be (without a clock the USART doesn't work)
RCC->APB1ENR |= (1<<18); // enable clock for USART
And as an additional hint, do not use all these magic numbers for the bits.
This is much more readable (and the needed defines are already done in the CMSIS:
RCC->APB1ENR |= RCC_APB1ENR_USART3EN; // enable clock for USART
After some research, I found there were more problems than just the clock not being enabled. Below is the complete code of the initialization for UART3 using an STM32F103RB chip
/*----------------------------------------------------------------------------
Initialize UART3 pins, Baudrate
*----------------------------------------------------------------------------*/
void USART3_Init (void) {
RCC->APB2ENR |= 1; // enable clock for AF
AFIO->MAPR |= AFIO_MAPR_USART3_REMAP_PARTIALREMAP; // set USART3 to partical remap to use PC10 and PC11
RCC->APB2ENR |= 1<<4; // enable clock for GPIOC
// since our pins are above 8, we use H instead of L
// since we are using 10 & 11 we will be using bits 8-15 in the CRH register
/* USART3 Tx (PC10) output push-pull */
GPIOC->CRH &= ~(0xFFUL << 8);
GPIOC->CRH |= (0x0BUL << 8);
/* USART3 Rx (PC11) input floating */
GPIOC->CRH |= (0x04UL << 12);
RCC->APB1ENR |= RCC_APB1ENR_USART3EN; /* enable clock for USART3 */
USART3->BRR = 0x138; /* set baudrate -115.2kB from 36MHz */
USART3->CR1 = (( 1UL << 2) | /* enable RX */
( 1UL << 3) | /* enable TX */
( 0UL << 12) ); /* 1 start bit, 8 data bits */
USART3->CR2 = 0x0000; /* 1 stop bit */
USART3->CR3 = 0x0000; /* no flow control */
USART3->CR1 |= 1<<13; /* USART3 enable */
//Configure and enable USART3 interrupt
NVIC->ICPR[USART3_IRQn/32] = 1UL << (USART3_IRQn%32); // clear any previous pending interrupt flag
NVIC->IP[USART3_IRQn] = 0x80; // set priority to 0x80
NVIC->ISER[USART3_IRQn/32] = 1UL << (USART3_IRQn%32); // set interrupt enable bit
USART3->CR1 |= USART_CR1_RXNEIE; // enable USART3 receiver not empty interrupt
}
and the interrupt I used to prove this works looks like this
// UART3 Interupt Handler
void USART3_IRQHandler (void) {
uint8_t inKey3 = (int8_t) (USART3->DR & 0x1FF);
SendCharTo3(inKey3);
if(inKey3 == 0x0D) {
SendCharTo3('\n');
}
}
/*----------------------------------------------------------------------------
SendChar
Write character to Serial Port. for UART 3
*----------------------------------------------------------------------------*/
int SendCharTo3 (uint8_t ch) {
while (!(USART3->SR & USART_SR_TXE));
USART3->DR = ((uint16_t)ch & 0x1FF);
return (ch);
}

STM32 & TLV5628 SPI Communication

Hi Everyone and thank you for your time.
I have been working on interfacing the STM32f446RE Nucleo board with the TLV5628 8 Bit Octal Serial DAC. I have ran into multiple issues, but the current issue has been one of two things:
1) The data and clock lines showing the exact same information
or
2) The data line showing information, but nothing on the clock line.
Regardless, the information coming out is completely incorrect.
Here is my setup code:
void SPI_INIT(void){
// Enable clocks for C
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOCEN;
// SPI GPIO
GPIOC->MODER |= 2 << 3*2; // PC3 data pin
GPIOC->MODER |= 2 << 7*2; // PC7 clock pin
GPIOC->MODER |= 1 << 2*2; //pc2 load
GPIOC->MODER |= 1 << 4*2; //pc4 ldac - probably set low permanently
// Pins default to push-pull
// set all to high speed
GPIOC->OSPEEDR |= (3 << 2*2) | (3 << 3*2) | (3 << 4*2) | (3 << 7*2);
GPIOC->AFR[0] |= 5<< 6*2; // Alt func 5 pc3 - SPI2
GPIOC->AFR[0] |= 5 << 7*2; // Alt func 5 pc7 - SPI2
// SPI Setup
RCC->APB1ENR |= RCC_APB1ENR_SPI2EN; // Enable SPI Clock
RCC->APB1RSTR |= RCC_APB1RSTR_SPI2RST; // reset SPI2
RCC->APB1RSTR &= ~RCC_APB1RSTR_SPI2RST;// clear the reset
// Control Register 1
SPI2->CR1 &= ~SPI_CR1_SPE; // Disable SPI
SPI2->CR1 |= SPI_CR1_MSTR; // master mode
SPI2->CR1 &= ~SPI_CR1_RXONLY; // transmit, 0 == full duplex
SPI2->CR1 &= ~SPI_CR1_DFF; // 8 bit format
SPI2->CR1 &= ~SPI_CR1_LSBFIRST; // MSB first
SPI2->CR1 &= ~SPI_CR1_CPOL;// low polarity, so 0 when idle
SPI2->CR1 |= 4 << 3; // (180M/4)/32 = 1.41 MHz
SPI2->CR1 |= SPI_CR1_CPHA; // first edge, look in data sheet
//Questionable settings
// Biderectional data line
SPI2->CR1 |= SPI_CR1_BIDIMODE; // 1/17/2019 --> Check to see if this fixes something
SPI2->CR1 |= SPI_CR1_BIDIOE; // idk if i need this
// CRC Polynomial Register
SPI2->CRCPR = 10;
// Control Register 2
SPI2->CR2 |= 1<<2; // SS output enabled
SPI2->CR1 |= SPI_CR1_SPE; // enable, has to be last
}
And here is my SPI Write code:
void SPI_Write(int dacSelect, int adcData){
while((SPI2->SR & SPI_SR_TXE) != 0);
GPIOC->ODR |= 1 << 2; // load set high to read data
SPI2->DR = dacArray[dacSelect]; // send address
SPI2->DR = adcData; // send adc data
while((SPI2->SR & SPI_SR_BSY) == SPI_SR_BSY);
GPIOC->ODR &= ~(1 << 2); // Send load low to load data
Delay(10); // short delay
GPIOC->ODR |= 1 << 2;
}
You can use STMCubeMX to generate codes for STM microprocessors and boards. Following code blocks are generated from STM32ubeMX for STM32F4. You should change baudrate for your sensor.
SPI_HandleTypeDef hspi;
SPI_HandleTypeDef SpiHandle;
void Spi_Initialize(void)
{
/*##-1- Configure the SPI peripheral #######################################*/
/* Set the SPI parameters */
SpiHandle.Instance = SPI2;
SpiHandle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;
SpiHandle.Init.Direction = SPI_DIRECTION_2LINES;
SpiHandle.Init.CLKPhase = SPI_PHASE_1EDGE;
SpiHandle.Init.CLKPolarity = SPI_POLARITY_LOW;
SpiHandle.Init.DataSize = SPI_DATASIZE_8BIT;
SpiHandle.Init.FirstBit = SPI_FIRSTBIT_MSB;
SpiHandle.Init.TIMode = SPI_TIMODE_DISABLE;
SpiHandle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
SpiHandle.Init.CRCPolynomial = 7;
SpiHandle.Init.NSS = SPI_NSS_SOFT;
SpiHandle.Init.Mode = SPI_MODE_MASTER;
if(HAL_SPI_Init(&SpiHandle) != HAL_OK)
{
while(1){};
}
}
void Spi_Read(void )
{
uint8_t SpiData[2];
uint8_t tempmessage = 8;
HAL_GPIO_WritePin(GPIOG,GPIO_PIN_8,RESET); // CS pin
HAL_SPI_TransmitReceive(&hspi,&tempmessage,SpiData,2,5000); // Read Data
HAL_GPIO_WritePin(GPIOG,GPIO_PIN_8,SET); // CS Pin
}
void Spi_Write(uint8_t *Data, uint8_t size)
{
HAL_GPIO_WritePin(GPIOG,GPIO_PIN_8,RESET); // CS pin
HAL_SPI_Transmit(&hspi, Data, size, 5000); // Write Data
HAL_GPIO_WritePin(GPIOG,GPIO_PIN_8,SET); // CS Pin
}

Simple DC motor Speed Control with Push Button

I'm running some tests on STM32L152 by trying to control a DC motor speed by selecting 3 different speeds using a push button, as following:
ideal mode, motor is off.
push button pressed, motor runs at speed-1
push button pressed again, motor runs at speed-2
push button pressed again, motor stops.
I've already tried to run the motor directly by setting CCR1 (TIM4), and it works perfectly. so I believe the only issue is with the push button part. here's the code:
#include <stdio.h>
#include "stm32l1xx.h" // Keil::Device:Startup
// initialization of GPIOB, GPIOA & PWM/TIM4
void GPIO_Init()
{
// initialization of GPIOB
RCC->AHBRSTR |= RCC_AHBRSTR_GPIOBRST; /* Reset GPIOB clock */
RCC->AHBENR |= RCC_AHBENR_GPIOBEN; /* Enable GPIOB clock*/
GPIOB->MODER &= ~(0x03 << (2 * 6)); /* Clear bit 12 & 13 Output mode*/
GPIOB->MODER |= 0x01 << (2 * 6); /* set as Output mode*/
GPIOB->OSPEEDR &= ~(0x03 << (2 * 6)); /* 40 MHz speed */
GPIOB->OSPEEDR |= 0x03 << (2 * 6); /* 40 MHz speed*/
GPIOB->PUPDR &= ~(1 << 6); /* NO PULL-UP PULL-DOWN*/
GPIOB->OTYPER &= ~(1 << 6); /* PUSH-PULL*/
GPIOB->AFR[0] |= 0x2 << (4 * 6);
// initialization of GPIOA
RCC->AHBRSTR |= RCC_AHBRSTR_GPIOARST; /* Reset GPIOA clock*/
RCC->AHBENR |= RCC_AHBENR_GPIOAEN; /* Enable GPIOA clock*/
GPIOA->MODER &= ~(0x03); /* Clear & set as input*/
GPIOA->OSPEEDR &= ~(0x03); /* 2 MHz speed */
GPIOA->OSPEEDR |= 0x01; /* 2 MHz speed */
GPIOA->PUPDR &= ~(0x03); /* No PULL-UP/DOWN */
GPIOA->OTYPER &= ~(0x1); /* PUSH-PULL */
//initialization of PWM & TIM4
RCC->APB1ENR |= RCC_APB1ENR_TIM4EN;
TIM4->PSC = 100;
TIM4->ARR = 414; // F=2.097MHz , Fck= 2097000/(100+1)= 20.762KHz, Tpwm = 0.02, ARR= (Fck x Tpwm)-1
TIM4->CCMR1 |= TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2; // 111: PWM mode 1
TIM4->CCMR1 |= TIM_CCMR1_OC1PE;
TIM4->CR1 |= TIM_CR1_ARPE;
TIM4->CCER |= TIM_CCER_CC1E;
TIM4->EGR |= TIM_EGR_UG;
TIM4->SR &= ~TIM_SR_UIF;
TIM4->DIER |= TIM_DIER_UIE;
TIM4->CR1 |= TIM_CR1_CEN;
}
// Delay conf
void setSysTick(void)
{
// ---------- SysTick timer (1ms) -------- //
if (SysTick_Config(SystemCoreClock / 1000))
{
// Capture error
while (1)
{
};
}
}
volatile uint32_t msTicks; //counts 1ms timeTicks
void SysTick_Handler(void)
{
msTicks++;
}
static void Delay(__IO uint32_t dlyTicks)
{
uint32_t curTicks = msTicks;
while ((msTicks - curTicks) < dlyTicks);
}
int returnVal = 0;
int updatedpress = 0;
int buttonpress() // function to check & add, if the pushbutton is pressed
{
if (GPIOA->IDR & GPIO_IDR_IDR_0) //condition: if PA0 is set
{
Delay(500); // avoid debouncing
if (GPIOA->IDR & GPIO_IDR_IDR_0) //confirm condition: if PA0 is set
{
returnVal = 1 + updatedpress;
while (GPIOA->IDR & GPIO_IDR_IDR_0)
{
}
}
}
return returnVal;
}
int main(void)
{
GPIO_Init();
setSysTick();
while (1)
{
int buttonpress();
updatedpress = returnVal;
if (updatedpress == 1)
TIM4->CCR1 = 30;
else if (updatedpress == 2)
TIM4->CCR1 = 37;
else if (updatedpress == 3)
TIM4->CCR1 = 46;
else if (updatedpress > 3)
returnVal = 0;
}
}
When I run the code, nothing works physiclly. I tried to run the debugger and I found that it exits the buttonpress function immedtialy after reaching
if(GPIOA->IDR & GPIO_IDR_IDR_0)
Any idea why it doesn't work as it should?
The GPIO peripherals are held in reset, you should clear the reset bits:
RCC->AHBRSTR |= RCC_AHBRSTR_GPIOBRST
RCC->AHBRSTR &= ~RCC_AHBRSTR_GPIOBRST
/* ... */
RCC->AHBRSTR |= RCC_AHBRSTR_GPIOARST;
RCC->AHBRSTR &= ~RCC_AHBRSTR_GPIOARST;
Ok it worked, and here are the corrections made:
1/ PB6 (which is connected to the DC motor) was mistakenly set as output. changed to Alternate Function.
2/ If-Conditions used for comparing the number of button-press and select motor speed is shifted to a separate function called runmotor
3/ The read instruction if(GPIOA->IDR & 0x0001) is moved into the while loop within the main function to ensure a continuous check of the pushbutton condition.
4/ Reset of GPIOs are cleared, as advised by #berendi
here's the updated code:
#include <stdio.h>
#include "stm32l1xx.h" // Keil::Device:Startup
// initialization of GPIOB, GPIOA & PWM/TIM4
void GPIO_Init(){
// initialization of GPIOB
RCC->AHBRSTR |= RCC_AHBRSTR_GPIOBRST; /* Reset GPIOB clock*/
RCC->AHBRSTR &= ~RCC_AHBRSTR_GPIOBRST; /* Clear Reset */
RCC->AHBENR |= RCC_AHBENR_GPIOBEN; /* Enable GPIOB clock*/
GPIOB->MODER &= ~(0x03 << (2*6)); /* Clear bit 12 & 13 */
GPIOB->MODER |= 0x02 << (2*6); /* set as Alternate function*/
GPIOB->OSPEEDR &= ~(0x03<< (2*6)); /* 40 MHz speed*/
GPIOB->OSPEEDR |= 0x03<< (2*6); /* 40 MHz speed */
GPIOB->PUPDR &= ~(1<<6); /* NO PULL-UP PULL-DOWN*/
GPIOB->OTYPER &= ~(1<<6); /* PUSH-PULL*/
GPIOB->AFR[0] |= 0x2 << (4*6);
// initialization of GPIOA
RCC->AHBRSTR |= RCC_AHBRSTR_GPIOARST; /* Reset GPIOA clock */
RCC->AHBRSTR &= ~RCC_AHBRSTR_GPIOARST; /* Clear Reset */
RCC->AHBENR |= RCC_AHBENR_GPIOAEN; /* Enable GPIOA clock */
GPIOA->MODER &= ~(0x03); /* Clear & set as input */
GPIOA->OSPEEDR &= ~(0x03); /* 2 MHz speed */
GPIOA->OSPEEDR |= 0x01; /* 2 MHz speed */
GPIOA->PUPDR &= ~(0x03); /* reset PULL-DOWN */
GPIOA->OTYPER &= ~(0x1); /* PUSH-PULL */
//initialization of PWM & TIM4
RCC->APB1ENR |= RCC_APB1ENR_TIM4EN;
TIM4->PSC = 100;
TIM4->ARR = 414; // F=2.097MHz , Fck= 2097000/(100+1)= 20.762KHz, Tpwm = 0.02, ARR= (Fck x Tpwm)-1
TIM4->CCMR1 |= TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2; // 111: PWM mode 1
TIM4->CCMR1 |= TIM_CCMR1_OC1PE;
TIM4->CR1 |= TIM_CR1_ARPE;
TIM4->CCER |= TIM_CCER_CC1E;
TIM4->EGR |= TIM_EGR_UG;
TIM4->SR &= ~TIM_SR_UIF;
TIM4->DIER |= TIM_DIER_UIE;
TIM4->CR1 |= TIM_CR1_CEN;
}
void setSysTick(void){
// ---------- SysTick timer (1ms) -------- //
if (SysTick_Config(SystemCoreClock / 1000)) {
// Capture error
while (1){};
}
}
volatile uint32_t msTicks; //counts 1ms timeTicks
void SysTick_Handler(void) {
msTicks++;
}
static void Delay(__IO uint32_t dlyTicks){
uint32_t curTicks = msTicks;
while ((msTicks - curTicks) < dlyTicks);
}
int buttonpress=0;
static void runmotor(void)
{
if (buttonpress ==1){
TIM4->CCR1 = 30;
return;
}
if (buttonpress ==2){
TIM4->CCR1 = 37;
return;
}
if (buttonpress ==3){
TIM4->CCR1 = 46;
return;
}
if (buttonpress > 3){
TIM4->CCR1 = 0;
buttonpress = 0;
return;
}
}
int main(void){
GPIO_Init();
setSysTick();
while (1){
if(GPIOA->IDR & 0x0001)
{
Delay(5);
if(GPIOA->IDR & 0x0001)
buttonpress = buttonpress + 1;
runmotor();
}
}
}

4 bit 4x20 LCD with Atmega32

I'm having trouble with my 4x20 LCD display.
I've been looking at a numerous guides and code snippets the last few days, but nothing seems to help.
The problem is that the displays shows nothing.
When I compile it on my computer and print it all on my screen, everything seems to be ok.
I would appreciate it if somebody would look through it and see if there are any obvious errors.
Thanks in advance.
// Connection:
//
// Atmega32 LCD
// PB0 -> DB4
// PB1 -> DB5
// PB2 -> DB6
// PB3 -> DB7
// PB4 -> RS
// PB5 -> R/W
// PB6 -> E
// PB7 ->
#include <avr/io.h>
#include <util/delay.h>
#define LCDPort PORTB
#define LCDDDR DDRB
#define enable 6 //Enable = on
#define readWrite 5 //Read = on, Write = off
#define RS 4 //Send command = off, send data = on
void checkBusy(void);
void updateLCD(void);
void sendCommand(unsigned char command);
void sendData(unsigned char character);
void sendInitCommand(unsigned char command);
int main(void)
{
LCDDDR |= 15;
LCDDDR |= 1 << enable; //Set control lines as output (high)
LCDDDR |= 1 << readWrite;
LCDDDR |= 1 << RS;
_delay_ms(100); //Wait for LCD to boot
sendInitCommand(0x3); //Init function set 1
_delay_ms(100);
sendInitCommand(0x3); //Init function set 2
_delay_us(100);
sendInitCommand(0x3); //Init function set 3
_delay_us(100);
sendInitCommand(0x2); //Function set (set 4 bit mode)
_delay_us(100);
sendInitCommand(0x28); //Funcion set I=1, N=0, F=0
//sendInitCommand(0x8);
_delay_us(60);
sendInitCommand(0x8); //On/off control D=0, C=0, B=0
//sendInitCommand(0x8);
_delay_us(60);
sendCommand(0x01); //Clear display
//sendInitCommand(0x1);
_delay_ms(60);
sendCommand(0x06); //Entry mode set I/D=1, S=0
//sendInitCommand(0x6);
_delay_us(60);
sendCommand(0x0C); //On/off control D=1, C=0, B=0
//sendInitCommand(0xC);
_delay_us(60);
sendData(0x41); //Display "A"
sendData(0x42); //Display "B"
sendData(0x43); //Display "C"
sendData(0x44); //Display "D"
sendData(0x45); //Display "E"
while(1) {
}
return 0;
}
void checkBusy() {
LCDDDR &= ~15; //Set data DDR lines read (low)
/* LCDPort |= 1 << readWrite; //Forget read for now - use delay instead
LCDPort &= ~1 << RS;
while((LCDPort & 15) >= 0x8) {
updateLCD();
}
*/
_delay_ms(50);
LCDDDR |= 15; //Set data lines DDR to write (high)
}
void updateLCD() {
LCDPort |= 1 << enable; //Enable
asm volatile ("nop");
asm volatile ("nop");
LCDPort &= ~1 << enable; //Disable
}
void sendCommand(unsigned char command) {
checkBusy();
LCDPort &= ~(1 << readWrite | 1 << RS); //Set R/W and RS low (write command)
LCDPort |= (command >> 4) & 15; //Send 4 ms bits
updateLCD();
LCDPort &= ~15;
LCDPort |= command & 15; //Send 4 ls bits
updateLCD();
LCDPort &= ~15; //Clear data lines
}
void sendData(unsigned char character) {
checkBusy();
LCDPort &= ~1 << readWrite; //Set R/W low and RS high (write data)
LCDPort |= 1 << RS;
LCDPort |= (character >> 4 & 15); //Send 4 ms bits
updateLCD();
LCDPort &= ~1 << readWrite;
LCDPort &= ~15;
LCDPort |= 1 << RS;
LCDPort |= (character & 15); //Send 4 ls bits
updateLCD();
LCDPort &= ~15; //Clear data lines
}
void sendInitCommand(unsigned char command) {
LCDPort &= ~(1 << readWrite | 1 << RS); //Set R/W and RS low (write command)
LCDPort |= command & 15;
updateLCD();
LCDPort &= ~15; //Clear data lines
}
Seems this is a HD44780 compatible Controller.
Note that every 4x20 Display is a 2x40 in real which is cutted in the middle. This can be implemented with one Display Controller, but the Display need several Drivers.
Get an eyeful of this:
nonetheless you can interface the Display in 4-Bit Mode.
Here is a sample how to Interface the 4x20 in Bit Mode
(note that Pin15 (LED+) and Pin16 (LED-) are missing, thats only the backlight pins). Dont forget to connect Pin5 (R/W) to GND.
A very good lib to interfacing a HD44780 4x20 is written by Peter Fleury:
http://homepage.hispeed.ch/peterfleury/avr-software.html#libs
in section "LCD library for HD44870 based LCD's" give it a try

Resources