1

I'm trying to make an i2c scanner (just like the arduino one) for the STM8S005K6 but I can't seem to even generate a start condition for the communication to begin.

I have to say, I've never used STM8 or the STVD IDE and I'm learning by myself with the limited information that is available.

I've looked in two or three forums on how to use I2C, but there is something on my particular case that is stopping me from getting it to work. I have connected to my I2C bus a BMP180 (address 0x77).

The code execution always gets stuck on while(!I2C_CheckEvent(I2C_EVENT_MASTER_MODE_SELECT)).

Here is the code:

/* MAIN.C file
 * 
 * Copyright (c) 2002-2005 STMicroelectronics
 */

#include "stm8s.h"
#include <string.h>

void setup(void);
void __delay_ms(unsigned int);
void UART2_SendString(char *, int );
char* itoa(int num, char* str, int base);
void reverse(char s[]);

main(){
    setup();
    I2C_DeInit();
    I2C_Init(100000, 0x00, I2C_DUTYCYCLE_2, I2C_ACK_CURR, I2C_ADDMODE_7BIT, (CLK_GetClockFreq() / 1000000));
    I2C_Cmd(ENABLE);
    
    UART2_SendString("STM8 INIT OK!\n\r", 20);
    while (1){
        char error, address, tmp[20];
        int nDevices;

        UART2_SendString("Scanning...\n\r", 20);

        nDevices = 0;
        for(address = 1; address < 127; address++) {
            
            UART2_SendString("START\n\r", 10);
            I2C_GenerateSTART(ENABLE);
            while(!I2C_CheckEvent(I2C_EVENT_MASTER_MODE_SELECT));
   
            UART2_SendString("ADDR\n\r", 10);
            I2C_Send7bitAddress(address, I2C_DIRECTION_TX); 
            while(!I2C_CheckEvent(I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
            
            UART2_SendString("STOP\n\r", 10);
            I2C_GenerateSTOP(ENABLE);
            
            error = I2C_CheckEvent(I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);
    
            if (error == SET) {
                UART2_SendString("I2C device found at address 0x", 40);
                if (address < 16) 
                    UART2_SendString("0", 10);
                itoa(address, tmp, 16);
                UART2_SendString(tmp, 10);
                UART2_SendString("\n\r", 10);

                nDevices++;
            }
            else if (error == 4) {
                UART2_SendString("Unknown error at address 0x", 40);
                if (address < 16) 
                    UART2_SendString("0", 10);
                itoa(address, tmp, 16);
                UART2_SendString(tmp, 10);
                UART2_SendString("\n\r", 10);
            }    
        }
        if (nDevices == 0)
            UART2_SendString("No I2C devices found\n\r", 40);
        else
            UART2_SendString("done\n\r", 10);

        __delay_ms(5000);           // wait 5 seconds for next scan
    }
}

void setup(void){
    CLK_DeInit();
    /* Configure the Fcpu to DIV1*/
    CLK_SYSCLKConfig(CLK_PRESCALER_CPUDIV1);
    /* Configure the HSI prescaler to the optimal value */
    CLK_SYSCLKConfig(CLK_PRESCALER_HSIDIV1);
    /* Configure the system clock to use HSI clock source and to run at 16Mhz */
    CLK_ClockSwitchConfig(CLK_SWITCHMODE_AUTO, CLK_SOURCE_HSI, DISABLE, CLK_CURRENTCLOCKSTATE_DISABLE);
    CLK_PeripheralClockConfig(CLK_PERIPHERAL_SPI, DISABLE);
  CLK_PeripheralClockConfig(CLK_PERIPHERAL_I2C, ENABLE);
  CLK_PeripheralClockConfig(CLK_PERIPHERAL_ADC, DISABLE);
  CLK_PeripheralClockConfig(CLK_PERIPHERAL_AWU, DISABLE);
  CLK_PeripheralClockConfig(CLK_PERIPHERAL_UART2, ENABLE);
  CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER1, DISABLE);
  CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER2, DISABLE);
    CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER3, DISABLE);
    CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER4, ENABLE);
    
    TIM4_DeInit();
    /* Configure Timer4 to prescaler 1:16 */
    TIM4_PrescalerConfig(TIM4_PRESCALER_16, TIM4_PSCRELOADMODE_UPDATE);
    /* Make Timer4 reset every 99 counts (100us) */
    TIM4_SetAutoreload(99);
    
    UART2_DeInit();
    UART2_Init(9600, UART2_WORDLENGTH_8D, UART2_STOPBITS_1, UART2_PARITY_NO, UART2_SYNCMODE_CLOCK_DISABLE, UART2_MODE_TX_ENABLE);
    
    GPIO_DeInit(GPIOB);
    GPIO_Init(GPIOB, GPIO_PIN_4, GPIO_MODE_OUT_OD_HIZ_FAST);
    GPIO_Init(GPIOB, GPIO_PIN_5, GPIO_MODE_OUT_OD_HIZ_FAST);
    
    GPIO_DeInit(GPIOD);
    GPIO_Init(GPIOD, GPIO_PIN_4, GPIO_MODE_OUT_PP_HIGH_SLOW);
}

void __delay_ms(unsigned int period){
    unsigned int m = 0, u = 0;
    TIM4_SetCounter(0);                                                                             // Reset counter for good measure
    TIM4_Cmd(ENABLE);                                                                                   // Enable Timer4
    for (m = 0; m <= period; m++){                                                          // Counts miliseconds
        for (u = 0; u <= 10; u++){                                                                  //Counts every 100 microseconds
            while(TIM4_GetFlagStatus(TIM4_FLAG_UPDATE) == RESET);               //Wait for Timer4 update flag to be set
            TIM4_ClearFlag(TIM4_FLAG_UPDATE);                                                       // Clear update flag
        }
    }
    TIM4_Cmd(DISABLE);                                                                              // Disable Timer4 when done
}

void UART2_SendString(char *str, int max_length){
    int i = 0;
    for (i = 0; i < max_length && str[i] != '\0'; i++) {
        GPIO_WriteHigh(GPIOD, GPIO_PIN_4);
        while(UART2_GetFlagStatus(UART2_FLAG_TXE) == RESET);
        UART2_SendData8(str[i]);
        GPIO_WriteLow(GPIOD, GPIO_PIN_4);
    }
    GPIO_WriteLow(GPIOD, GPIO_PIN_4);
}

char* itoa(int num, char* str, int base){
    int i = 0;
    bool isNegative = 0;
 
    /* Handle 0 explicitly, otherwise empty string is printed for 0 */
    if (num == 0)
    {
        str[i++] = '0';
        str[i] = '\0';
        return str;
    }
 
    // In standard itoa(), negative numbers are handled only with
    // base 10. Otherwise numbers are considered unsigned.
    if (num < 0 && base == 10)
    {
        isNegative = 1;
        num = -num;
    }
 
    // Process individual digits
    while (num != 0)
    {
        int rem = num % base;
        str[i++] = (rem > 9)? (rem-10) + 'a' : rem + '0';
        num = num/base;
    }
 
    // If number is negative, append '-'
    if (isNegative)
        str[i++] = '-';
 
    str[i] = '\0'; // Append string terminator
 
    // Reverse the string
    reverse(str);
 
    return str;
}

void reverse(char s[]){
     int i, j;
     char c;
 
     for (i = 0, j = strlen(s)-1; i<j; i++, j--) {
         c = s[i];
         s[i] = s[j];
         s[j] = c;
     }
 }

I'm using the STM8S_StdPeriph_Lib from the ST Official Website.

fpp
  • 159
  • 9
  • 1
    Have you stepped into I2C_CheckEvent in the debugger? Have you checked what event I2C_CheckEvent is returning? – Tyler Dec 15 '22 at 20:08
  • I2C_CheckEvent is returning always ERROR. The weird thing is that while looking on some I2C examples, they use ```while (I2C_GetFlagStatus(I2C_FLAG_BUSBUSY));```. In my particular case, the BUSBUSY flag seems to be 1, so there is something (nothing) on the bus that makes the module think the bus is busy, thus making CheckEvent return ERROR. I have tried disconnecting everything, but still no luck. Checking with a diy logic analyzer, i see that both SDA and SCL are always 3.3v. What else could it be? – fpp Dec 16 '22 at 17:25
  • Do you have pull up resistors? – carlossp Jan 08 '23 at 14:39
  • Yes. 4k7ohm resistors – fpp Jan 09 '23 at 15:50

1 Answers1

3

Maybe a bit late for your issue but it might help someone else.

Did you program the option byte AFR6 bit? (AFR = Alternate Function Register)

In case of the STM8S105, AFR6 determines whether B5 and B4 can be used as SCL and SDA or not. If you are new to STM8S like I am, probably you didn't. ;-) This explains why your SDA and SCL is always 3.3V.

Solution: You can use e.g. STVP (or another tool) to program the option byte.