#ESP32 MCU learning notes - 02 - Software IIC & hardware SPI

Posted by reyjrar on Fri, 18 Feb 2022 18:11:02 +0100

ESP32 MCU learning notes - 02 - Software IIC & hardware SPI

Preface, continue the content of the previous article. In order not to accumulate too much content, write it separately.

1, ESP32 read gyroscope (IIC)

Official routine: github:esp-idf/examples/peripherals/i2c/i2c_self_test/ iic is the official software used by iic before.
Official guidelines: I2C driver I2C is a serial synchronous half duplex communication protocol. Multiple master and slave computers can be mounted on the bus at the same time. I2C bus is composed of serial data line (SDA) and serial clock line (SCL). These lines need pull-up resistors, I used software pull-up. (this one is introduced in Chinese)
Tutorial notes: Chapter 12 ESP32 reading temperature and humidity (IIC) of SHT30 , I didn't read the first example myself. I just read the official guide. In fact, if the official guide is in Chinese, it is better to read the official guide.
Data book: ESP32 technical reference manual , in Chapter 11 of PDF: I2C controller (I2C).

  • The first step is to use the familiar software iic. I use zhufei technology directly RT1064 Library The software iic in is deducted. Note that I took the CH32V103 library at first, but found that there was no content to change the output and input direction in the library, so I changed the RT1064 with the change of input and output direction. although esp32 manual I saw a pattern on the: GPIO_MODE_INPUT_OUTPUT, which reads: "GPIO mode: input / output mode". But I haven't used it for the time being. I'll study its meaning later. Now use GPIO first_ MODE_ Input input mode and GPIO only_ MODE_ Output only output mode, and then use GPIO_ set_ The direction function can be switched. (these functions are found in the manual. You can find the new world by checking them yourself.)

  • After getting the template of software iic, you only need to change the relevant macro definitions of SDA and SCL, and then change the initialization pin function. The length of the software delay has not been changed. Try it first. In mpu6050 There are two hardware delay calls in C, which can be changed to vtask delay in FreeRTOS of esp32. Another step is that the names of data types are different. We should add a suffix to nouns such as uint8 to change them into uint8_t. Otherwise, an error will be reported. Then, the others don't need to be changed. Zhufei has been encapsulated. It's really good.

#define SEEKFREE_SCL    GPIO_NUM_18 / / define SCL pin, which can be changed to other IO at will
#define SEEKFREE_SDA    GPIO_NUM_19 / / define SDA pin, which can be changed to other IO at will

#define SDA             gpio_get_level (SEEKFREE_SDA)
#define SDA0()          gpio_ set_ Level (seekfree_sda, 0) / / IO port output low level
#define SDA1()          gpio_ set_ Level (seekfree_sda, 1) / / IO port output high level  
#define SCL0()          gpio_ set_ Free0 / / level, free0 (SCIO)
#define SCL1()          gpio_ set_ Level (seekfree_scl, 1) / / IO port output high level
#define DIR_OUT()       gpio_set_direction (SEEKFREE_SDA, GPIO_MODE_OUTPUT) / / output direction
#define DIR_IN()        gpio_set_direction (SEEKFREE_SDA, GPIO_MODE_INPUT) / / enter the direction

void simiic_init(void)
{
    gpio_config_t io_conf;
    //disable interrupt
    io_conf.intr_type = GPIO_INTR_DISABLE;
    //set as output mode
    io_conf.mode = GPIO_MODE_OUTPUT;
    //bit mask of the pins that you want to set,e.g.SDA
    io_conf.pin_bit_mask = ((1ULL<<SEEKFREE_SCL) | (1ULL<<SEEKFREE_SDA));   // Top priority!!!!!!!!!!!!!
    //disable pull-down mode
    io_conf.pull_down_en = 0;
    //disable pull-up mode
    io_conf.pull_up_en = 1;
    //configure GPIO with the given settings
    gpio_config(&io_conf);
}

In fact, there is no instance at the beginning. The initialization pin is the card owner. Print the log content in the serial port (note that it is the content with color, so it can be judged that it is log printing, which does not belong to manual printing): I (309) gpio: GPIO[0]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 1| Pul. It's very strange, because I clearly initialized the IO18 and IO19 pins. Why is the IO0 pin displayed here. And every time I get stuck here, I can't go on to the next step. Then I found a note: esp8266 ~ obtain mpu6050 six axis sensor data [wifi balance trolley can be made on this basis] . Among them, this prompt means reporting an error. However, the error content should at least correspond to the pin number, and it is 2 lines. I came back and found it was me GPIO_ The config pin configuration is wrong, and the pin_bit_mask should put the displacement number of 1 instead of pure number. In the previous uart, the function initialization pin or the key is also the function quick initialization pin, which is filled with pure digital io slogans. However, if the structure is initialized, a displacement conversion operation should be added. Then it succeeded. Print out the following contents: (because the card owner of the program is, and I don't have the online debugging function, so I set the printing steps in the program to prompt me which card owner is. In addition, it seems that a prompt will be generated after the initialization pin?)

I (297) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
app_main Start - 01
simiic_init Start - 02
I (309) gpio: GPIO[18]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
I (319) gpio: GPIO[19]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
simiic_init Start - 03
mpu6050_self1_check Start - 04
mpu6050 There are several reasons for being stuck here
simiic_write_reg Start - 05
mpu_acc_x = 1
mpu_acc_x = 71
mpu_acc_x = 57
mpu_acc_x = 63
mpu_acc_x = 47
mpu_acc_x = 65
mpu_acc_x = 69
mpu_acc_x = 55
mpu_acc_x = 55
mpu_acc_x = 185
mpu_acc_x = -2
mpu_acc_x = -2050
mpu_acc_x = -1026
mpu_acc_x = 15
mpu_acc_x = 243
mpu_acc_x = 37
mpu_acc_x = 53
  • Hardware iic will not be transplanted. I will directly look at the transplantation of hardware spi. It should be similar, but also to speed up the progress.

2, ESP32 drives IPS color display (SPI)

Official routine: github:esp-idf/examples/peripherals/spi_master/lcd/ , there is an official routine about lcd. I only read the basic sending and receiving and initialization, but I didn't see other data processing. Because I have a corresponding library, I just need to care about the underlying configuration.
Official guidelines: SPI Master Driver , it is introduced in English again, with a big head. Because I used to call api, I didn't care about the protocol or configuration. I only know that it is similar to iic. It also raises and lowers cs, selects devices, and sends sending addresses, commands, and data.
Data book: ESP32 technical reference manual , in Chapter 7 of PDF: SPI controller (SPI).

At first, I thought that I could transplant the flying library and the bottom of the eps official routine together and use it. As a result, I struggled for a long time, but I still failed. Checked a note on the same hardware configuration: ESP32 device SPI main device driver , compared with the official, they tried to change it together, but failed. After tossing for a long time, I want to try the software simulation spi, because the software iic has been successful, and the software spi should also be very simple. Then I also refer to a note: (ESP32 learning 13) drive TFTLCD (SPI interface) . Woo woo, still failed. I can't think of it. It may be a problem... The following notes summarize the problems I found, but even so, it hasn't been successful at present. After that, it will be supplemented again (2021.05.04).
I didn't expect to be back so soon. The next morning, I asked little M. zhufei. He warmly received me and said he could help me have a look. When I was ready to ask him after I connected the line and downloaded the program, I found that it was successful and can be used!!! I shouldn't have changed anything. I just rewired the line. (I remember I downloaded it under the current configuration last night, but it didn't succeed)

  • Problems needing attention during initialization (found):
  1. esp32 has no spi, only hspi and vspi, but I don't know the difference between the three. At present, hspi is selected following the routine_ HOST;
  2. In the initialization process, first initialize the relevant pins and use spi_bus_initialize, and then configure various parameters spi_bus_add_device. Where clock_speed_hz frequency parameter, the maximum value of esp32 is 26. If it is greater than this number, an error will be reported during operation initialization; pre_cb specifies a callback function. I didn't know how to use it at first. Later, combined with the write data and write command, it is found that a parameter will be sent, and the function will be called to read the parameter each time. Change ips114 according to this_ DC_ Pin level. Therefore, it actually plays a role in changing the level. In the fly by fly library, this operation is performed manually before calling the write data or write command function. Finally, spi_bus_add_device also has an spi_device_handle_t-type parameter, which feels like a handle, will be passed in every time the spi operation is called. It originally refers to the spi.
//-----------------Pin definition------------------------------
#define IPS114_SPIN_PIN         HSPI_HOST / / defines the SPI number used (esp32 only has hspi or vspi?!)
#define IPS114_ SCL_ Pin 19 / / define SPI_SCK pin
#define IPS114_ SDA_ Pin 23 / / define SPI_MOSI pin
#define IPS114_ SDA_ IN_ Pin 25 / / define SPI_MISO pin IPS has no MISO pin, but it still needs to be defined here. It needs to be used in the initialization of spi
#define IPS114_ CS_ Pin 22 / / define SPI_CS pin
#define IPS114_DC_PIN  	         twenty-one 	            // LCD command bit pin definition

spi_device_handle_t ips114_spi;

//This function is called (in irq context!) just before a transmission starts. It will
//set the D/C line to the value indicated in the user field.
// Used to trigger the callback function, and then pull up the level in the callback function
void lcd_spi_pre_transfer_callback(spi_transaction_t *t)
{
    int dc=(int)t->user;
    gpio_set_level(IPS114_DC_PIN, dc);
    // printf("dc\n");
}

void spi_init(void)
{
    gpio_set_direction(IPS114_DC_PIN, GPIO_MODE_OUTPUT);
    gpio_set_level(IPS114_DC_PIN, 0);

    esp_err_t ret;
    spi_bus_config_t buscfg={
        .miso_io_num=IPS114_SDA_IN_PIN,
        .mosi_io_num=IPS114_SDA_PIN,
        .sclk_io_num=IPS114_SCL_PIN,
        .quadwp_io_num=-1,
        .quadhd_io_num=-1,
    };
    spi_device_interface_config_t devcfg={
        // .command_bits = 8,
        // .address_bits = 24,
        .clock_speed_hz=26*1000*1000,           //Clock out at 26 MHz (max)
        .mode=0,                                //SPI mode 0 SPI mode 0: cpol = 0 CPHA = 0 1: cpol = 0 CPHA = 1 2: cpol = 1 CPHA = 0 3: CPOL=1 CPHA=1 / / please click Baidu for details
        .spics_io_num=IPS114_CS_PIN,            //CS pin
        .queue_size=7,                          //We want to be able to queue 7 transactions at a time
        .pre_cb=lcd_spi_pre_transfer_callback,  //Specify pre-transfer callback to handle D/C line
    };
    //Initialize the SPI bus
    ret=spi_bus_initialize(IPS114_SPIN_PIN, &buscfg, 0);
    ESP_ERROR_CHECK(ret);
    //Attach the LCD to the SPI bus
    ret=spi_bus_add_device(IPS114_SPIN_PIN, &devcfg, &ips114_spi);
    ESP_ERROR_CHECK(ret);
}
  • Problems needing attention when writing data / commands (found):
  1. Whether sending or receiving, SPI is used_ device_ polling_ The transmit function, where is the configuration spi_transaction_t type is determined by data.
  2. The function of the parameter flags is to specify tx_data array or tx_buffer pointer to put data. If not configured, the default is to use pointers. The pointer used in the routine, and then I see that in the notes written by others, I use the array, because zhufei originally used the array to split 16 bit data, so I also used the array. But I've tried both. I don't know why they didn't succeed.
  3. The function of the parameter length, and in particular, is to count in bits, so it is calculated by multiplying the number of bytes by 8.
  4. In addition to data, there are many other parameters of this structure that can be configured, such as addr and cmd. It seems that the comments refer to the address and command respectively. But the routines are stored in data. That is, send the command as data. So I infer that it should play the same role, just for the convenience of management.
void lcd_cmd(const uint8_t cmd)
{
    esp_err_t ret;
    spi_transaction_t t;
    memset(&t, 0, sizeof(t));       //Zero out the transaction
    t.flags=SPI_TRANS_USE_TXDATA;   //
    t.length=8;                     //Command is 8 bits
    t.tx_data[0]=cmd;               //The data is the cmd itself
    t.user=(void*)0;                //D/C needs to be set to 0 is used to trigger the callback function and change the level of DC pin
    ret=spi_device_polling_transmit(ips114_spi, &t);  //Transmit!
    assert(ret==ESP_OK);            //Should have had no issues.
}

void lcd_data(const uint8_t data[2], int len)
{
    esp_err_t ret;
    spi_transaction_t t;
    if (len==0) return;             //no need to send anything
    memset(&t, 0, sizeof(t));       //Zero out the transaction
    t.user=(void*)1;                //D/C needs to be set to 1
    t.flags=SPI_TRANS_USE_TXDATA;
    if(len == 1)
    {
        t.length=8;
        t.tx_data[0]=data[0];        //Data
    }
    else if(len == 2)
    {
        t.length=2*8;
        t.tx_data[0]=data[0];
        t.tx_data[1]=data[1];
    }
    else
    {
        assert(1);
    }
    ret=spi_device_polling_transmit(ips114_spi, &t);  //Transmit!
    assert(ret==ESP_OK);            //Should have had no issues.
}

Additional interesting knowledge points, ESP_ERROR_CHECK and assert; There is a special chapter in the manual: error handling . I find this function very easy to use. If the configuration is wrong, the wrong content will be printed directly in the terminal. The printed content is even specific to which file line, which is much better than the one used before (referring to MCU or library). In the past, if the configuration is wrong, the hardware error interrupt will be directly dropped, or there is no phenomenon. It takes a long time to find a problem, especially when you can't debug online.

  • Record so much first, and then supplement it if it is found that it is a problem later. (22:05:21, May 4, 2021) no problem was found, but the problem has disappeared... (09:57:14, May 5, 2021)

Topics: Single-Chip Microcomputer ESP32