STM32F407: I2C1 not working with LCD1602 display. Bare metal
Hi
my first attempt to program a LCD1602 via I2C1 on my STM32F407 discovery board failed miserably. I do not get the start condition generated, which means I never get the Start bit (SB) set in my status register. It seems that I am missing something fundamentally in my setup. Intention: STM32F407 is master, LCD is slave. The I2C module on my LCD seems to be the PCF8574, with address 0x27 (A0, A1 and A2 are logic high).
Any sharp eyes around that can spot my mistake? Thank you.
EDIT:
My code get stuck in line 42, where it never leaves the while loop.
My code:
#include "stm32f4xx.h"
// I2C1 using PB6 and PB7 as AF.
// PB6: I2C1_SCL; PB7: I2C1_SDA
// I2C driver used in LCD 1602: PCF8574
int main(void)
{
// 1. Setting up GPIO to I2C
// 1.0 Sets PB6 and PB7 to Alternate Function
GPIOB->MODER |= (2<<GPIO_MODER_MODER6_Pos); // Sets PB6 to AF
GPIOB->MODER |= (2<<GPIO_MODER_MODER7_Pos); // Sets PB7 to AF
// 1.1 PB6 and PB7 open drain
GPIOB->OTYPER |= ((1<<GPIO_OTYPER_OT6_Pos) | (1<<GPIO_OTYPER_OT7_Pos));
// 3. PB6 and PB7 no Pull up/down
GPIOB->PUPDR &= ~((3U<<GPIO_PUPDR_PUPD6_Pos) | (3U<<GPIO_PUPDR_PUPD7_Pos));
// 1.2 PB6 and PB7 to AF4
GPIOB->AFR[0] |= (4U<<GPIO_AFRL_AFSEL6_Pos);
GPIOB->AFR[0] |= (4U<<GPIO_AFRL_AFSEL7_Pos);
// 2. Setting up I2C1
// 2.0 Enable APB1 Bus
RCC->APB1ENR |= (1<<RCC_APB1ENR_I2C1EN_Pos); // Enables I2C1 on APB1 line
// 1. Step: Configure the mode (SM, FM, FM+)
// 2. Step: Configure the speed (100kHz, 400kHz etc.)
I2C1->CR2 |= (16U<<I2C_CR2_FREQ_Pos); // HSI is used. 16MHz
I2C1->CCR &= ~(1<<I2C_CCR_FS_Pos); // Standard mode SM
I2C1->CCR |= (80U<<I2C_CCR_CCR_Pos); // CCR=Thigh/TPCLK1=0.5*(1/100kHz)/(1/16MHz)=80
// 4. Step: Enable ACK
I2C1->CR1 |= (1<<I2C_CR1_ACK_Pos); // Enable acknowledge
// 5. Step: Configure rise time for I2C pins.
I2C1->TRISE |= (17<<I2C_TRISE_TRISE_Pos);
I2C1->CR1 |= (1<<I2C_CR1_PE_Pos);
// Sending data
// Generate start condition
I2C1->CR1 |= (1<<I2C_CR1_START_Pos); // Generate repeated start condition
while(!(I2C1->SR1 & I2C_SR1_SB_Pos)); // Wait until Start bit is set
uint8_t tempAddress = 0;
uint8_t slaveAddress = 39; // 0x27 = 39dec = 0b0010 0111
tempAddress = (slaveAddress<<1); // Make space on the 0th bit for R/W
tempAddress &= ~(1<<0); // Clear 0th bit for write
I2C1->DR |= tempAddress;
while(!(I2C1->SR1 & I2C_SR1_ADDR_Pos));
while(!(I2C1->SR1 & I2C_SR1_TXE_Pos));
I2C1->DR = 100;
while(!(I2C1->SR1 & I2C_SR1_TXE_Pos));
while(!(I2C1->SR1 & I2C_SR1_BTF_Pos));
I2C1->CR1 |= (1<<I2C_CR1_STOP_Pos);
I2C1->CR1 &= ~(1<<I2C_CR1_PE_Pos); // Turn off I2C1
for(;;);
}