STM8S I2C ADDR Register Not Setting

Thread Starter

AaronD13

Joined Mar 16, 2017
4
I am currently working with the STM8S Discovery using the on board STM8S003K3. At the moment I am attempting to establish the I2C communication using the MCU in master mode.

However, I am having an issue whilst setting up the communication channel. I have chosen to poll at each stage waiting for the corresponding flags to be set but after writing the address to the Data Register (and measuring the correct output via oscilloscope) I am stuck polling the ADDR bit in the SR1 register.

As it stands the MCU is not actually communicating with anything directly (possible acknowledgement error?) but I am presuming that the ADDR bit will be set by hardware regardless, if not, is this bit set on the receipt of an ACK?

Any suggestions would be greatly appreciated!

**P.S:- I am not using the STD Peripheral libraries.
 

Thread Starter

AaronD13

Joined Mar 16, 2017
4
Code:
typedef struct I2C_CR1_Struct
{
volatile uint8 PE  : 1;  // Peripheral Enable
volatile uint8 RES1  : 1;  // RESERVED AREA 1
volatile uint8 RES2  : 1;  // RESERVED AREA 2
volatile uint8 RES3  : 1;  // RESERVED AREA 3
volatile uint8 RES4  : 1;  // RESERVED AREA 4
volatile uint8 RES5  : 1;  // RESERVED AREA 5
volatile uint8 ENGC  : 1;  // General Call Enable
volatile uint8 NONSTRETCH : 1; // Clock Stretching Disable (Slave Mode)
}I2C_CR1;

typedef struct I2C_CR2_Struct
{
volatile uint8 START : 1;  // Start Generation
volatile uint8 STOP  : 1;  // Stop Generation
volatile uint8 ACK  : 1;  // Acknowledge Enable
volatile uint8 POS  : 1;  // Acknowledge Position
volatile uint8 RES1  : 1;  // RESERVED AREA 1
volatile uint8 RES2  : 1;  // RESERVED AREA 2
volatile uint8 RES3  : 1;  // RESERVED AREA 3
volatile uint8 SWRST : 1;  // Software Reset
}I2C_CR2;

typedef struct I2C_SR1_Struct
{
volatile const uint8 SB  : 1;  // Start Bit
volatile const uint8 ADDR  : 1;  // Address Sent
volatile const uint8 BTF  : 1;  // Byte Transfer Finished
volatile const uint8 ADD10 : 1;  // 10 Bit Header Sent
volatile const uint8 STOPF : 1;  // Stop Detection
volatile const uint8 RES1  : 1;  // RESERVED AREA 1
volatile const uint8 RXNE  : 1;  // Data Register Not Empty
volatile const uint8 TXE  : 1;  // Data Register Empty
}I2C_SR1;

typedef struct I2C_SR2_Struct
{
volatile uint8 BERR : 1;  // Bus Error
volatile uint8 ARLO : 1;  // Arbitration Lost
volatile uint8 AF  : 1;  // Acknowledge Failure
volatile uint8 OVR  : 1;  // Overrun/Underrun
volatile uint8 RES1 : 1;  // RESERVED AREA 1
volatile uint8 WUFH : 1;  // Wake Up From Halt
volatile uint8 RES2 : 1;  // RESERVED AREA 2
volatile uint8 RES3 : 1; // RESERVED AREA 3
}I2C_SR2;

typedef struct I2C_Struct
{
volatile  I2C_CR1 CR1;   // I2C Control Register 1
volatile  I2C_CR2 CR2;   // I2C Control Register 1
volatile  uchar  FREQR;   // I2C Frequency Register
volatile  uchar  OARL;   // I2C Own Address Register Low
volatile  uchar  OARH;   // I2C Own Address Register High
  uchar  RES1; // RESERVED AREA 1
volatile  uchar  DR;   // I2C Data Register
volatile  I2C_SR1 SR1;   // I2C Status Register 1
volatile  I2C_SR2 SR2;   // I2C Status Register 2
volatile const uchar  SR3;   // I2C Status Register 3
volatile  uchar  ITR;   // I2C Interrupt Control Register
volatile  uchar  CCRL;   // I2C Clock Control Register Low
volatile  uchar  CCRH;   // I2C Clock Control Register High
volatile  uchar  TRISER; // I2C TRISE Register
volatile  uchar  PECR;   // I2C Packet Error Checking Register
}I2C_REG;

/* ------------------------------ I2C BASE ADDRESS ----------------------------- */
#define I2C_BASE 0x005210
/* ---------------------------- I2C REGISTER GATEWAY --------------------------- */
#define I2C ((I2C_REG*) I2C_BASE)

void I2C_Init(void);
void I2C_OpenComms(uchar DATA, bool RW);
#endif

/* ------------------------------- HEADER FILES -------------------------------- */
#include "I2C.h"
#include "LIS3DH.h" // Provides ADDRESS

void I2C_Init(void)
{
I2C->CR1.PE  = 0;  // Disable I2C
// Clear FLAGS
I2C->SR2.BERR = 0;
I2C->SR2.ARLO = 0;
I2C->SR2.AF  = 0;
I2C->SR2.OVR  = 0;
I2C->SR2.WUFH = 0;
// Program peripheral input clock in I2C_FREQ Register
I2C->FREQR &= 0xC0;
I2C->FREQR |= 0x10; // 16MHz
// Configure clock control registers
I2C->CCRL &= 0x00;  // Reset CCRL
I2C->CCRH &= 0x30;  // Reset CCRH
   /// 400kHZ - FAST MODE - 16MHz
I2C->CCRL |= 0x0D; // Set CCRL
I2C->CCRH |= 0x80; // Set F/S = 1

// Configure the rise time register
I2C->TRISER &= 0x00;  // Reset TRISER
/// 400kHZ - FAST MODE - 16MHz
I2C->TRISER |= 0x05;  // Set TRISER: (300ns/(1/16M) = 4+1 = 5)
I2C->CR2.ACK = 1;
I2C->CR2.POS = 1;
I2C->CR1.PE  = 1;  // Re-Enable I2C
}


void I2C_OpenComms(uchar DATA, bool RW)
{
if(!I2C->CR1.PE) // Peripheral Not Enabled
{
I2C_Init();
}
I2C->CR2.START = 1;
  while(!I2C->SR1.SB){;}
if(RW = FALSE) // Write to device
{
I2C->DR = (uchar)((ADDRESS<<1) & 0xFE);

}
else  // Read from device
{
I2C->DR = (uchar)((ADDRESS<<1) | 0x01);
}
while( (I2C->SR1.ADDR == 0) ){;} // Wait for the ADDR bit to be set
}
Edit: Moderator added code tags
 

MrChips

Joined Oct 2, 2009
30,824
You are making life more difficult than it needs to be.

Learn to use CubeMX, HAL and associated library routines. You are missing basic module initialization functions. Every hardware module needs bus and clock initialization.

Look at some STM32 example code and learn how to initialize a simple I/O function.
 

Thread Starter

AaronD13

Joined Mar 16, 2017
4
Sorry, for simplicity I have only included the I2C related code.

By default all peripheral clocks are enabled, the corresponding I2C pins (PB4 - SCL & PB5 - SDA) have been initialised as output open drain with initial HIZ state and fast clock rate.

As mentioned, I have already scoped the outputs of the clock and data line and they are behaving correctly in outputting the slave address. The issue occurs in the firmware when polling the ADDR bit of Status Register 1 which is shown on line 127 above. According to the reference manual, upon transmission of the 7 bit slave address and direction bit this should be set by hardware but is not.

I understand the provided libraries would make this much easier but I am required to do this from scratch.
 
Top