SylixOS GPIO imitating I2C bus driver development process based on STM32 platform

  1. Overview

    This document takes the STM32F767 platform as an example to introduce the driver development process of GPIO imitating I2C bus on SylixOS in detail.

     

  2. initialization

    The initialization of the I2C bus imitated by GPIO is actually the initialization of the GPIO pins of SDA and SCL of the I2C bus. The initialization process is shown in Figure 2.1.

    Figure 2.1 I2C initialization flow chart

    Code implementation, as shown in program listing 2.1. The GPIO speed of the SDA and SCL GPIO pins of the I2C bus should be set to fast mode, and the output mode should be set to push-pull output mode.

    Program listing 2.1 I2C initialization code

    /*
         * Apply for GPIO of SCL of I2C 1 channel
         */
        if (ERROR_NONE != API_GpioRequest(I2C1_CHANNEL_SCL, I2C1_SCL_GPIO_NAME)) {
            return  (PX_ERROR);
        }
    
        /*
         * Set pull up
         */
        if (ERROR_NONE != API_GpioSetPull(I2C1_CHANNEL_SCL, GPIO_PUPD_PU)) {
            return  (PX_ERROR);
        }
    
        /*
         * Set to push-pull output mode, and GPIO speed is fast
         */
        if (ERROR_NONE != API_GpioDirectionOutput(I2C1_CHANNEL_SCL,
                                                  		   (GPIO_SPEED_SET 	|
                                                  		    GPIO_OTYPE_SET 	|
                                                   	    LW_GPIOF_INIT_HIGH))) {
            return  (PX_ERROR);
        }
    
        /*
         * Apply for GPIO of SDA of I2C 1 channel
         */
        if (ERROR_NONE !=  API_GpioRequest(I2C1_CHANNEL_SDA, I2C1_SDA_GPIO_NAME)) {
            return  (PX_ERROR);
        }
        if (ERROR_NONE != API_GpioSetPull(I2C1_CHANNEL_SDA, GPIO_PUPD_PU)) {
            return  (PX_ERROR);
        }
        if (ERROR_NONE != API_GpioDirectionOutput(I2C1_CHANNEL_SDA,
                                                  		   (GPIO_SPEED_SET 	|
                                                  		    GPIO_OTYPE_SET 	|
                                                   	    LW_GPIOF_INIT_HIGH))) {
            return  (PX_ERROR);
        }
  3. transfer process

    The biggest difference between the GPIO analog I2C bus driver and the ordinary I2C bus driver is that the data transmission of the ordinary I2C bus driver only needs to write the data to be transmitted into the register, while the data transmission of the GPIO analog I2C bus driver is directly through the GPIO pin. The level is pulled high and low (pulled high is 1, pulled low is 0) to transmit data.

  4. write data flow

    As shown in the program listing 3.1, the I2C write data flow is as follows:

    1. The master device sends a start signal;

    2. The master device sends 7-bit slave device address and 1-bit write operation bit;

    3. Send a reply signal from the device;

    4. The master device sends the 8-bit slave device internal address to be written;

    5. Send a reply signal from the device;

    6. The master device starts to write to the slave device;

    7. The master device sends the end signal.

    Program listing 3.1 I2C write data flow

    static INT  __i2cXferWrite (UINT             uiChannel,
                                PLW_I2C_MESSAGE pI2cMsg,
                                INT              iLength)
    {
        INT  iIndex;
    
        __i2cStart(uiChannel); /* Send start signal*/
    
        /*
         * Send 7-bit device address and 1-bit write bit
         */
        __i2cSendByte((pI2cMsg->I2CMSG_usAddr & I2C_ADDR_MASK), uiChannel);
    
        if (__i2cWaitAck(uiChannel)) { /* wait for the ACK signal from the device*/
            _DebugHandle(__ERRORMESSAGE_LEVEL, "__i2cXferWrite(): Timeout to wait ack!\r\n");
    
            return  (PX_ERROR);
        }
    
        /*
         * Send the internal address of the device to read
         */
        __i2cSendByte(((pI2cMsg->I2CMSG_usAddr) & I2C_INTER_ADDR_MASK), uiChannel);
        if (__i2cWaitAck(uiChannel)) { /* wait for the ACK signal from the device*/
            _DebugHandle(__ERRORMESSAGE_LEVEL, "__i2cXferWrite(): Timeout to wait ack!\r\n");
    
            return  (PX_ERROR);
        }
    
        for (iIndex = 0; iIndex < iLength; iIndex++) {
            __i2cSendByte(*(pI2cMsg->I2CMSG_pucBuffer)++, uiChannel); /* send byte*/
            if (__i2cWaitAck(uiChannel)) { /* wait for the ACK signal from the device*/
                _DebugHandle(__ERRORMESSAGE_LEVEL, "__i2cXferWrite(): Timeout to wait ack!\r\n");
    
                return  (PX_ERROR);
            }
        }
    
        __i2cStop(uiChannel); /* Generate a stop signal */
    
        udelay(I2C_WRITE_BYTE_DELAY);
    
    
        return (ERROR_NONE);
    }
  5. read data flow

    As shown in the program listing 3.2, the read data flow of I2C is as follows:

    1. In write mode, the master device sends a start signal;

    1. The master device sends 7-bit slave device address and 1-bit write operation bit;

    2. Send a reply signal from the device;

    3. The master device sends the 8-bit slave device internal address to be written;

    4. Send a reply signal from the device;

    5. Enter the read mode, the device sends the start signal again;

    6. The master device sends 7-bit slave device address and 1-bit read operation bit;

    7. Send a reply signal from the device;

    8. The master device starts to read the slave device;

    9. The master device sends the end signal.

    Program Listing 3.2 I2C Read Data Flow

static INT  __i2cXferRead (UINT             uiChannel,
                           PLW_I2C_MESSAGE pI2cMsg,
                           INT              iLength)
{
    INT  iIndex;

    __i2cStart(uiChannel); /* Send start signal*/

    /*
     * Send 7-bit device address and 1-bit write operation bit, (bits 9-15 in I2CMSG_usAddr are device address)
     */
    __i2cSendByte(((pI2cMsg->I2CMSG_usAddr >> 8) & I2C_ADDR_MASK), uiChannel);

    if (__i2cWaitAck(uiChannel)) { /* wait for the ACK signal from the device*/
        _DebugHandle(__ERRORMESSAGE_LEVEL, "__i2cXferWrite(): Timeout to wait ack!\r\n");

        return  (PX_ERROR);
    }

    /*
     * Send the internal address of the device to read
     */
    __i2cSendByte(((pI2cMsg->I2CMSG_usAddr) & I2C_INTER_ADDR_MASK), uiChannel);
    if (__i2cWaitAck(uiChannel)) { /* wait for the ACK signal from the device*/
        _DebugHandle(__ERRORMESSAGE_LEVEL, "__i2cXferWrite(): Timeout to wait ack!\r\n");

        return  (PX_ERROR);
    }

    /*
     * enter read mode
     */
    __i2cStart(uiChannel); /* Send start signal*/

    /*
     * Send 7-bit device address and 1-bit read operation bit, (8-15 bits in I2CMSG_usAddr are device address and read and write bits)
     */
    __i2cSendByte(((pI2cMsg->I2CMSG_usAddr >> 8) & I2C_ADDR_MASK) | LW_I2C_M_RD, uiChannel);
    if (__i2cWaitAck(uiChannel)) { /* wait for the ACK signal from the device*/
        _DebugHandle(__ERRORMESSAGE_LEVEL, "__i2cXferWrite(): Timeout to wait ack!\r\n");

        return  (PX_ERROR);
    }

    for (iIndex = 0; iIndex < iLength - 1; iIndex++) {

        /*
         * Read 1 byte of data sent by the device
         */
        *(pI2cMsg->I2CMSG_pucBuffer)++ = __i2cReadByte(I2C_ACK_SEND, uiChannel);
    }

    *(pI2cMsg->I2CMSG_pucBuffer) = __i2cReadByte(I2C_NACK_SEND, uiChannel);

    __i2cStop(uiChannel); /* Generate stop signal */


    return  (ERROR_NONE);
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325027658&siteId=291194637