2015-05-17 12:28 PM
I've been trying to work out how to make the STM8S act as an I2C slave and to be honest I'm failing. I think I've set everything up according to the reference manual but for some reason I'm not getting the expected interrupts being fired.
I have a Netduino setup as an I2C master. The logic analyser and the scope both show a write and an address of 0x02 and a NAK being generated on the I2C bus.I was expecting the STM8S to generate an ACK and an interrupt to request data or to send data. At the very least I was expecting an interrupt to be generated.I know the interrupt handler is being wired up as I get an error interrupt when I recompile the Netduino code and it redeploys. At this time it messes up the I2C bus.The STM8S application code is:#include <iostm8s103f3.h>#include <intrinsics.h>//// I2C interrupts all share the same handler.//#pragma vector = I2C_RXNE_vector__interrupt void I2C_IRQHandler(){ if (I2C_SR1_RXNE) { unsigned char data; data = I2C_DR; } if (I2C_SR1_TXE) { I2C_DR = 0xaa; // Some dummy data to send. }}//// Setup the system clock.//void InitialiseSystemClock(){ CLK_ICKR = 0; // Reset the Internal Clock Register. CLK_ICKR_HSIEN = 1; // Enable the HSI. CLK_ECKR = 0; // Disable the external clock. while (CLK_ICKR_HSIRDY == 0); // Wait for the HSI to be ready for use. CLK_CKDIVR = 0; // Ensure the clocks are running at full speed. CLK_PCKENR1 = 0xff; // Enable all peripheral clocks. CLK_PCKENR2 = 0xff; // Ditto. CLK_CCOR = 0; // Turn off CCO. CLK_HSITRIMR = 0; // Turn off any HSIU trimming. CLK_SWIMCCR = 0; // Set SWIM to run at clock / 2. CLK_SWR = 0xe1; // Use HSI as the clock source. CLK_SWCR = 0; // Reset the clock switch control register. CLK_SWCR_SWEN = 1; // Enable switching. while (CLK_SWCR_SWBSY != 0); // Pause while the clock switch is busy.}//// Setup I2C.//void InitialiseI2C(){ I2C_CR1_PE = 0; // Diable I2C before configuration starts. // // Setup the clock information. // I2C_FREQR = 16; // Set the internal clock frequency (MHz). I2C_CCRH_F_S = 0; // I2C running is standard mode. I2C_CCRL = 0xa0; // SCL clock speed is 50 KHz. I2C_CCRH_CCR = 0x00; // // Set the address of this device. // I2C_OARL_ADD = 0x02; // Seven bit address. I2C_CR1_ENGC = 1; // Enable the general call address. I2C_OARH_ADDMODE = 0; // 7 bit address mode. I2C_OARH_ADDCONF = 1; // Docs say this must always be 1. // // Setup the bus characteristics. // I2C_CR2_ACK = 1; I2C_TRISER = 17; // // Turn on the interrupts. // I2C_ITR_ITBUFEN = 1; // Buffer interrupt enabled. I2C_ITR_ITEVTEN = 1; // Event interrupt enabled. I2C_ITR_ITERREN = 1; // // Configuration complete so turn the peripheral on. // I2C_CR1_PE = 1;}int main(){ __disable_interrupt(); InitialiseSystemClock(); InitialiseI2C(); __enable_interrupt(); while (1) { __wait_for_interrupt(); }}Can anyone see where I'm going wrong?Regards,Markl2015-05-18 09:56 AM
I took a quick peek at the datasheet and it seems the ACK bit is forced low while PE is off, so you may need to raise it late.
Beyond that I'd suggest taking a peek at the reference implementation and example code in the application libraries.2015-05-19 11:30 PM
Thanks for taking the time to look at the code. I'll give that a go.
I'm sure I've got the clock setup OK as I've put the I2C into master mode and I can get an address out of the system with a clock running at 50KHz.I read the manual as ''set everything up before enabling the peripheral'' and looking at how I got the master working I think you are going to be right. I need to split the set up of the peripheral from the bus control.Regards,Mark2015-05-23 11:41 AM
Johan was spot on. I moved the statement I2C_CR2_ACK = 1 to a point where the peripheral was enabled (i.e. after I2C_CR1_PE = 1) and I now have a working slave receiver.
Thanks for the help Johan - greatly appreciated.Regards,Mark