Im using two stm32l152 discovery boars. One is configured as master and the other as slave. I have acknowladge enabled on both of them, but when the master sends the address the slave doesn't send the ack bit at the 9 clock pulse. The ports are set to alternate function 4 and to open drain. I am using external 4.7k pullup resistors to 3.3V. I've checked all the registers multiple times and I don't know why the slave doesn't recognizes it's address.
This is the output from the logic analyser
D3 is the start bit from the master
D4 is the addres matched bit on the slave.
This is the slave code:
#define USE_STDPERIPH_DRIVER
#include "stm32l1xx.h"
#include "stm32l1xx_conf.h"
//Quick hack, approximately 1ms delay
void ms_delay(int ms)
{
while (ms> 0) {
volatile int x = 5971;
while (x> 0) {
x--;
}
ms--;
}
}
#define SCL 8
#define SDA 9
int main(void)
{
RCC->AHBENR |= (0x1 << 1);
//set port to alternate function
GPIOB->MODER &= ~((0x3 << (2 * SCL)) | (0x3 << (2 * SDA)) | (0x3 << (2 * 5)));
GPIOB->MODER |= ((0x2 << (2 * SCL)) | (0x2 << (2 * SDA)) | (0x1 << (2 * 5)));
GPIOB->OTYPER |= ((1 << SCL) | (1 << SDA)); //set output PB6 and PB7 to open drain
//set PB6 and PB7 to no pullup no pulldown
GPIOB->PUPDR &= ~((0x3 << (2 * SCL)) | (0x3 << (2 * SDA)) | (0x3 << (2 * 5)));
//set PB6 and PB7 to alternate function 4(I2C)
GPIOB->AFR[1] &= ~((0b1111 << (4 * 0)) | (0b1111 << (4 * 1)));
//set PB6 and PB7 to alternate function 4(I2C)
GPIOB->AFR[1] |= ((0b0100 << (4 * 0)) | (0b0100 << (4 * 1)));
RCC->APB1ENR |= (1 << 21);
//reset I2C
I2C1->CR1 |= (1 << 15);
ms_delay(1);
I2C1->CR1 &= ~(1 << 15);
I2C1->CR2 |= 0b001000; //peripheral clock set to 8MHz
I2C1->CR1 |= (1 << 10); //ACK enabled
I2C1->OAR1 |= (0x05 << 1); //setting primary address
I2C1->CR1 |= 1; //I2C peripheral enabled when configuration is done
for (;;) {
if ((I2C1->SR1&(1 << 1)) != 0) {
GPIOB->ODR |= (1 << 5);
}
else {
GPIOB->ODR &= ~(1 << 5);
}
}
}
This is the master code:
#define USE_STDPERIPH_DRIVER
#include "stm32l1xx.h"
#include "stm32l1xx_conf.h"
#define SCL 8
#define SDA 9
int main(void)
{
RCC->AHBENR |= (0x1 << 1);
//set port to alternate function
GPIOB->MODER &= ~((0x3 << (2 * SCL)) | (0x3 << (2 * SDA)) | (0x3 << (2 * 5)));
GPIOB->MODER |= ((0x2 << (2 * SCL)) | (0x2 << (2 * SDA)) | (0x1 << (2 * 5)));
//set output PB6 and PB7 to open drain
GPIOB->OTYPER |= ((1 << SCL) | (1 << SDA));
//set PB6 and PB7 to no pullup no pulldown
GPIOB->PUPDR &= ~((0x3 << (2 * SCL)) | (0x3 << (2 * SDA)) | (0x3 << (2 * 5)));
//set PB6 and PB7 to alternate function 4(I2C)
GPIOB->AFR[1] &= ~((0b1111 << (4 * 0)) | (0b1111 << (4 * 1)));
//set PB6 and PB7 to alternate function 4(I2C)
GPIOB->AFR[1] |= ((0b0100 << (4 * 0)) | (0b0100 << (4 * 1)));
I2C1->CR1 |= (1 << 15);
I2C1->CR1 &= ~(1 << 15);
RCC->APB1ENR |= (1 << 21);
I2C1->CR2 |= 0x08; //peripheral clock set to 8MHz
I2C1->CCR |= 0x28; //
I2C1->TRISE |= 0x09;
I2C1->CR1 |= (1 << 10); //ACK enabled
I2C1->CR1 |= 1; //I2C peripheral enabled when configuration is done
I2C1->CR1 |= (1 << 8); //generate start condition (master mode)
for (;;) {
//check start condition
if ((I2C1->SR1&(1 << 0)) != 0) {
GPIOB->ODR |= (1 << 5);
I2C1->DR = 0x0b << 0; //send slave addres
}
else {
GPIOB->ODR &= ~(1 << 5);
}
if ((I2C1->SR1&(1 << 1)) != 0) {
GPIOB->ODR |= (1 << 5);
}
else {
GPIOB->ODR &= ~(1 << 5);
}
}
}
Im compiling with arm-none-eabi-gcc and using the stsw-stm32077 librarys from stm
The problem with the code is that you have to set the ack bit after the peripheral is enabled, if you do it before, the ack bit gets automatically reset.