tenbaht / sduino

An Arduino-like programming API for the STM8
http://tenbaht.github.io/sduino/
GNU Lesser General Public License v2.1
347 stars 213 forks source link

Lack of example of using I2C. Event interrupts not implemented? #143

Open rtek1000 opened 2 years ago

rtek1000 commented 2 years ago

Hello,

I found some example usage codes on the Internet, but I couldn't get the MCP4725 to work, I tested it with Arduino Nano and it worked.

Test code for Arduino Nano:

  while (1) {
    Wire.beginTransmission(0x62);
    Wire.write(0x0F);
    Wire.write(0xFF);
    Wire.write(0x0);
    Wire.write(0x0);
    Wire.endTransmission();
  }

Unfortunately I still couldn't get the I2C port to work correctly, there are some posts that say they had problems with I2C on these STM8S, and in my case the I2C_GetFlagStatus() function seems to be unable to read the register and so the routine freezes. The problem seems to be the lack of interrupt, because the initialization of the I2C module does not trigger interrupt events, so asking the code to wait for an interrupt, the code is stuck forever. Basically I found two initializations, one that activates the interrupt and one that does not activate.

This other file shows the activation of the interrupt on line 88, I've tried working with the interrupt, but it's a bit complex, and I believe you need to faithfully follow the steps outlined in ST's RM0016 document:

  // ------------------------ Interrupts are enabled ------------------------
  I2C1_ITR_ITEVTEN = 1; //Event  Enables               : SB, ADDR, ADD10, STOPF, BTF, WUFH
  I2C1_ITR_ITBUFEN = 1; //Buffer Enables (if ITEVTEN)  : RXNE, TXE
  I2C1_ITR_ITERREN = 1; //Error  Enables               : BERR, ARLO, AF, OVR

https://github.com/HomeSmartMesh/STM8_IoT_HelloWorld/blob/master/18_STM8L_HelloI2C/i2c.c

It would be interesting to have an example of functional usage for I2C in the folder: https://github.com/tenbaht/sduino/tree/development/test Or: https://github.com/tenbaht/sduino/tree/development/examples

P.S.: Ref.: https://www.st.com/en/embedded-software/stsw-stm8004.html https://www.st.com/resource/en/application_note/an3281-stm8-8bit-mcus-ic-optimized-examples-stmicroelectronics.pdf

rtek1000 commented 2 years ago

Hi, I managed to make the MCP4725 work, I filtered an example of the AN3281 from ST, here are the routines that worked:

(Note: My MCP4725 froze more than once (eventually) when trying out different settings in the I2C routines. Be aware that it may be necessary to use a MOSFET or relay to reset the MCP4725 via programming, or manually switch the power supply in the event of a communication failure)

Usage (MCP4725) dac_test.ino:

#include"stm8s.h"
#include "stm8s_i2c.h"

#define MCP4725_Addr 0x62
#define uC_Addr 0x1
#define I2C_Speed 100000

void setup (void);
void loop (void);
void I2C_WriteRegister2(u8 u8_regAddr, u8 u8_NumByteToWrite, u8 *u8_DataBuffer);
void I2C_Setup(u8 u8_regAddr);

void setup (void) {
    I2C_Setup(uC_Addr); // 
}

void loop (void) {
  u8 buff[2];

  while (1) {
    for (int i = 0; i < 4095; i++) {

      buff[0] = (i >> 8) & 0x0F;
      buff[1] = i & 0xFF;

      I2C_WriteRegister2(MCP4725_Addr, 2, buff);
    }
  }
}

/******************************************************************************
  Function name : I2C_WriteRegister2
  Description   : write defined number bytes to slave memory starting with defined offset
  Input param   : offset in slave memory, number of bytes to write, starting address to send
  Return        : None.
  See also      : i2c_master_poll.c - STM8 optimized I2C examples (AN3281)
*******************************************************************************/
void I2C_WriteRegister2(u8 u8_regAddr, u8 u8_NumByteToWrite, u8 *u8_DataBuffer)
{
  uint8_t I2C_Slave_Address = u8_regAddr << 1; // from 8 bits to 7 bits + R/W

  I2C_GenerateSTART(ENABLE);
  while ((I2C->SR1 & 1) == 0); // Wait for start bit detection (SB)

  I2C_Send7bitAddress(I2C_Slave_Address, I2C_DIRECTION_TX);
  while (!(I2C->SR1 & 2));     // Wait for address ack (ADDR)
  (void)I2C->SR3; // ADDR=1, cleared by reading SR1 register followed by reading SR3

  while (u8_NumByteToWrite--)
  { // write data loop start
    while (!(I2C->SR1 & 0x80));                 // test EV8 - wait for TxE
    I2C_SendData(*u8_DataBuffer++);                           // send next data byte
  }

  while ((I2C->SR1 & 0x84) != 0x84); // Wait for TxE & BTF

  I2C_GenerateSTOP(ENABLE);
  while (I2C->CR2 & 2); // wait until stop is performed
}

void I2C_Setup(u8 u8_regAddr)
{
  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);

  CLK_PeripheralClockConfig(CLK_PERIPHERAL_I2C, ENABLE);

  I2C_DeInit();

  I2C_Init(I2C_Speed, u8_regAddr, I2C_DUTYCYCLE_2, I2C_ACK_CURR, I2C_ADDMODE_7BIT, (CLK_GetClockFreq() / 1000000));

  // I2C->ITR = 1;                      // enable error interrupts
  //  I2C1_ITR_ITEVTEN = 1;          //Event  Enables               : SB, ADDR, ADD10, STOPF, BTF, WUFH
  //  I2C1_ITR_ITBUFEN = 1;          //Buffer Enables (if ITEVTEN)  : RXNE, TXE
  //  I2C1_ITR_ITERREN = 1;          //Error  Enables               : BERR, ARLO, AF, OVR

  I2C_Cmd(ENABLE);
}

Source code: https://github.com/rtek1000/RF_Magic_Controller_6803_IC/tree/main/Arduino_Modified_Hardware

Note: People put the device address in the I2C init, but it's the address of the uC (Host) in slave mode, don't confuse it.

I2C_Setup(uC_Addr)

Sample code:

https://www.st.com/content/my_st_com/en/products/embedded-software/mcu-mpu-embedded-software/stm8-embedded-software/stsw-stm8004.license=1658170455837.product=STSW-STM8004.version=1.0.0.html

stefaandesmet2003 commented 2 years ago

Why not use the examples provided with the wire library port included in the sduino repo? They work.

rtek1000 commented 2 years ago

Thanks for the feedback, actually I had only found a few examples for other compilers, and this document AN, but now that you mention Wire, I'll look for where it is and I'll try to use it, thanks again!

rtek1000 commented 2 years ago

https://github.com/tenbaht/sduino/tree/development/sduino/stm8/libraries/Wire

rtek1000 commented 1 year ago

Note: I tried adding the '#include ' declaration.

Before adding the declaration, it had 91% of used program space, and after adding the instruction #include the code started to occupy 105% of used program space (that is, it doesn't fit in memory in this case) we can see that using the Wire library takes up at least about 14% of the STM8S103F3's program space.

Using this code with the I2C_WriteRegister2 routine (cited above) the code now occupies only 96%. That is, if it is only to write to the I2C port, it may be interesting to have the routine separate, to save the program memory of only 8kB.