(C) ESP32 SPI Master drive SK68(RGB LED)

MarsONTU
Posts: 7
Joined: Tue May 03, 2022 4:14 am

(C) ESP32 SPI Master drive SK68(RGB LED)

Postby MarsONTU » Tue May 03, 2022 4:34 am

I'm tring to use ESP32-S3 SPI to drive SK68(which is a RGB LED),this led requires pulldown the signal transmission pin 80 us after once transmission (PS: pin also trgging at Microsecond level so I want to use SPI), But I can't find a way to set the SPI MOSI Pin.....

and here is my code: sure there is a better way, I just want to have a try

Code: Select all

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/spi_master.h"
#include "driver/gpio.h"
#include "unistd.h"
#include "sdkconfig.h"
#include "esp_log.h"

#define DMA_CHAN 2
#define PIN_NUM_MISO 41
#define PIN_NUM_MOSI 48
#define PIN_NUM_CLK 37
#define PIN_NUM_CS 41

#define CODE0 0xC0
#define CODE1 0xF1

static const char TAG[] = "main";

esp_err_t spi_write(spi_device_handle_t spi)
{

    esp_err_t ret;
    spi_transaction_t t;
    memset(&t, 0, sizeof(t)); // Zero out the transaction

    gpio_set_level(PIN_NUM_CS, 0);

    unsigned char Rbuffer = 0;
    unsigned char Gbuffer = 255;
    unsigned char Bbuffer = 255;
    unsigned char Data_buffer[24];
    unsigned char *p_data = Data_buffer;

    unsigned char mask = 0x80;
    unsigned char byte = Gbuffer;
    while (mask)
    {
        if (mask & byte)
        {
            *p_data = CODE1;
        }
        else
        {
            *p_data = CODE1;
        }
        mask >>= 1;
        p_data++;
    }
    mask = 0x80;
    byte = Rbuffer;

    while (mask)
    {
        if (mask & byte)
        {
            *p_data = CODE1;
        }
        else
        {
            *p_data = CODE1;
        }
        mask >>= 1;
        p_data++;
    }
    mask = 0x80;
    byte = Bbuffer;

    while (mask)
    {
        if (mask & byte)
        {
            *p_data = CODE1;
        }
        else
        {
            *p_data = CODE1;
        }
        mask >>= 1;
        p_data++;
    }

    t.length = 24 * 8;         // Len is in bytes, transaction length is in bits.
    t.tx_buffer = Data_buffer; // Data
    t.user = (void *)1;        // D/C needs to be set to 1

    ret = spi_device_polling_transmit(spi, &t); // Transmit!
    
    assert(ret == ESP_OK); // Should have had no issues.
    gpio_set_level(PIN_NUM_CS, 1);

    // gpio_reset_pin(PIN_NUM_MOSI);
    // gpio_pullup_dis(PIN_NUM_MOSI);
    // gpio_set_pull_mode(PIN_NUM_MOSI, GPIO_PULLDOWN_ONLY);
    // gpio_pulldown_en(PIN_NUM_MOSI);
    
    // gpio_set_level(PIN_NUM_MOSI, 0);
    // printf("Pin is %d\n",gpio_get_level(PIN_NUM_MOSI));
    

    return ret;
}

void app_main(void)
{
    esp_err_t ret;
    spi_device_handle_t spi;
    ESP_LOGI(TAG, "Initializing bus SPI%d...", SPI2_HOST + 1);

    spi_bus_config_t buscfg = {
        .miso_io_num = PIN_NUM_MISO, // MISO信号线
        .mosi_io_num = PIN_NUM_MOSI, // MOSI信号线
        .sclk_io_num = PIN_NUM_CLK,  // SCLK信号线
        .quadwp_io_num = -1,         // WP信号线,专用于QSPI的D2
        .quadhd_io_num = -1,         // HD信号线,专用于QSPI的D3
        .max_transfer_sz = 64 * 8,   // 最大传输数据大小
    };

    spi_device_interface_config_t devcfg = {
        .clock_speed_hz = APB_CLK_FREQ / 996, // Clock out at 10 MHz,
        .mode = 2,                            // SPI mode 0
        /*
         * The timing requirements to read the busy signal from the EEPROM cannot be easily emulated
         * by SPI transactions. We need to control CS pin by SW to check the busy signal manually.
         */
        .spics_io_num = -1,
        .queue_size = 7, // 传输队列大小,决定了等待传输数据的数量
    };

    // Initialize the SPI bus
    ret = spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO);
    ESP_ERROR_CHECK(ret);
    ret = spi_bus_add_device(SPI2_HOST, &devcfg, &spi);
    ESP_ERROR_CHECK(ret);

    gpio_pad_select_gpio(PIN_NUM_CS);                 // 选择一个GPIO
    gpio_set_direction(PIN_NUM_CS, GPIO_MODE_OUTPUT); // 把这个GPIO作为输出

    while (1)
    {
        spi_write(spi);
    }
}

ESP_Sprite
Posts: 9727
Joined: Thu Nov 26, 2015 4:08 am

Re: (C) ESP32 SPI Master drive SK68(RGB LED)

Postby ESP_Sprite » Tue May 03, 2022 4:51 am

Easiest way is to add a bunch of 0 bytes at the end of your SPI transaction.

MarsONTU
Posts: 7
Joined: Tue May 03, 2022 4:14 am

Re: (C) ESP32 SPI Master drive SK68(RGB LED)

Postby MarsONTU » Tue May 03, 2022 6:09 am

ESP_Sprite wrote: Easiest way is to add a bunch of 0 bytes at the end of your SPI transaction.
sorry that I don't get it, but it requires at least a continuous 80us level to as a reset signal, bunch of 0 seems can't reach it.
also I tried to release the SPI Bus then reset the GPIO(MOSI) and pull it down, this action will cost few ms to finish it so this can't be possible.

ESP_Sprite
Posts: 9727
Joined: Thu Nov 26, 2015 4:08 am

Re: (C) ESP32 SPI Master drive SK68(RGB LED)

Postby ESP_Sprite » Tue May 03, 2022 8:34 am

MarsONTU wrote:
Tue May 03, 2022 6:09 am
sorry that I don't get it, but it requires at least a continuous 80us level to as a reset signal, bunch of 0 seems can't reach it.
also I tried to release the SPI Bus then reset the GPIO(MOSI) and pull it down, this action will cost few ms to finish it so this can't be possible.
Why not? At 10MHz, 80uS is 800 bits or 100 bytes. That should be no issue for the SPI peripheral to clock out.

MarsONTU
Posts: 7
Joined: Tue May 03, 2022 4:14 am

Re: (C) ESP32 SPI Master drive SK68(RGB LED)

Postby MarsONTU » Tue May 03, 2022 11:58 am

ESP_Sprite wrote:
Tue May 03, 2022 8:34 am
MarsONTU wrote:
Tue May 03, 2022 6:09 am
sorry that I don't get it, but it requires at least a continuous 80us level to as a reset signal, bunch of 0 seems can't reach it.
also I tried to release the SPI Bus then reset the GPIO(MOSI) and pull it down, this action will cost few ms to finish it so this can't be possible.
Why not? At 10MHz, 80uS is 800 bits or 100 bytes. That should be no issue for the SPI peripheral to clock out.
yes...I think you're right about this way. I was confused because the " unipolar zeroing code " protocol before.

now these might be funny : (

I tried to extend the array numbers from 24 up to 340 (so the data length up to 340*8 bits) in order to delay low level ( Rest time ) time up to 80uS but failed. (It works when array numbers only have 250, but reset time still not enough)

Because I use DMA channel to send data, the useful Data int array is 24 bits and for each bits the minimum symbol period is 1.2μs so I set .clock_speed_hz = APB_CLK_FREQ / 996 ,for some reason it leads to program crash, it keeps reporting errors:
Guru Meditation Error: Core 0 panic'ed (Unhandled debug exception).
Debug exception reason: BREAK instr

So I don't think it's a good way to use SPI now.....
( plz forgive me if I act stupid! Also I am curious about your time zone because of your respond time by the way

ESP_Sprite
Posts: 9727
Joined: Thu Nov 26, 2015 4:08 am

Re: (C) ESP32 SPI Master drive SK68(RGB LED)

Postby ESP_Sprite » Wed May 04, 2022 12:51 am

Are you allocating the data array on the stack? If so, it may be overflowing that stack. Either increase the stack size of your main task, or use malloc()/free() to allocate/deallocate the buffer.

MarsONTU
Posts: 7
Joined: Tue May 03, 2022 4:14 am

Re: (C) ESP32 SPI Master drive SK68(RGB LED)

Postby MarsONTU » Wed May 04, 2022 7:31 am

ESP_Sprite wrote:
Wed May 04, 2022 12:51 am
Are you allocating the data array on the stack? If so, it may be overflowing that stack. Either increase the stack size of your main task, or use malloc()/free() to allocate/deallocate the buffer.
Good news: It's worked! though it still weird that I don't use a task to excute the spi mission(you mean main function is a task actually?) and it will cause stack overflowing. The fact is I just change the partition table :factory size to 2M and it success.

I first tried to use malloc&freeb to allocate the buffer in main and trainsmit it into my SPI process function, However it still cause overflowing till I change the partition table ( I'm not quit sure about it )

Thank you sooooo much for these advise!I still want to know how to increase the stack size of main task (partition?) so could you show me a way?

and here is my code(RGB color still have problems because I'm not technically according to the RGB LED protocol but if you change the RGB array it will change color):

Code: Select all

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/spi_master.h"
#include "driver/gpio.h"
#include "sdkconfig.h"
#include "esp_log.h"

#define DMA_CHAN 2
#define PIN_NUM_MISO 42
#define PIN_NUM_MOSI 48
#define PIN_NUM_CLK 37
#define PIN_NUM_CS 41

#define CODE0 0xC0
#define CODE1 0xF1

static const char TAG[] = "SPI";

esp_err_t spi_write(spi_device_handle_t spi, char *Datashit)
{
    esp_err_t ret;
    spi_transaction_t t;
    memset(&t, 0, sizeof(t)); // Zero out the transaction

    gpio_set_level(PIN_NUM_CS, 0);

    unsigned char data[400];
    unsigned char *p_data = data;

    unsigned char Rbuffer = 255;
    unsigned char Gbuffer = 0;
    unsigned char Bbuffer = 255;

    unsigned char mask = 0x80;
    unsigned char byte = Gbuffer;
    while (mask)
    {
        if (mask & byte)
        {
            *p_data = CODE1;
        }
        else
        {
            *p_data = CODE1;
        }
        mask >>= 1;
        p_data++;
    }
    mask = 0x80;
    byte = Rbuffer;

    while (mask)
    {
        if (mask & byte)
        {
            *p_data = CODE1;
        }
        else
        {
            *p_data = CODE1;
        }
        mask >>= 1;
        p_data++;
    }
    mask = 0x80;
    byte = Bbuffer;

    while (mask)
    {
        if (mask & byte)
        {
            *p_data = CODE1;
        }
        else
        {
            *p_data = CODE1;
        }
        mask >>= 1;
        p_data++;
    }
    int i;
    for(i=24;i<400;i++)
    {
        *p_data = CODE0;
        p_data++;
    }

    t.length = 400 * 8;                         // Len is in bytes, transaction length is in bits.
    t.tx_buffer = p_data;                       // Data
    t.user = (void *)1;                         // D/C needs to be set to 1
    ret = spi_device_polling_transmit(spi, &t); // Transmit!
    assert(ret == ESP_OK);                      // Should have had no issues.

    gpio_set_level(PIN_NUM_CS, 1);
    return ret;
}

void app_main(void)
{
    esp_err_t ret;
    spi_device_handle_t spi;
    ESP_LOGI(TAG, "Initializing bus SPI%d...", SPI2_HOST + 1);

    spi_bus_config_t buscfg = {
        .miso_io_num = PIN_NUM_MISO, // MISO信号线
        .mosi_io_num = PIN_NUM_MOSI, // MOSI信号线
        .sclk_io_num = PIN_NUM_CLK,  // SCLK信号线
        .quadwp_io_num = -1,         // WP信号线,专用于QSPI的D2
        .quadhd_io_num = -1,         // HD信号线,专用于QSPI的D3
        .max_transfer_sz = 64 * 8,   // 最大传输数据大小
    };

    spi_device_interface_config_t devcfg = {
        .clock_speed_hz = SPI_MASTER_FREQ_8M, // Clock out at 10 MHz,
        .mode = 0,                            // SPI mode 0
        /*
         * The timing requirements to read the busy signal from the EEPROM cannot be easily emulated
         * by SPI transactions. We need to control CS pin by SW to check the busy signal manually.
         */
        .spics_io_num = -1,
        .queue_size = 7, // 传输队列大小,决定了等待传输数据的数量
    };

    // Initialize the SPI bus
    ret = spi_bus_initialize(SPI2_HOST, &buscfg, SPI_DMA_CH_AUTO);
    ESP_ERROR_CHECK(ret);
    ret = spi_bus_add_device(SPI2_HOST, &devcfg, &spi);
    ESP_ERROR_CHECK(ret);

    gpio_pad_select_gpio(PIN_NUM_CS);                 // 选择一个GPIO
    gpio_set_direction(PIN_NUM_CS, GPIO_MODE_OUTPUT); // 把这个GPIO作为输出

    const char *Datashit;
    Datashit = (char *)malloc(45);

    spi_write(spi, *Datashit);

    while (1)
    {
        
    }
}

ESP_Sprite
Posts: 9727
Joined: Thu Nov 26, 2015 4:08 am

Re: (C) ESP32 SPI Master drive SK68(RGB LED)

Postby ESP_Sprite » Wed May 04, 2022 8:04 am

Your code always runs in a task, the main task is simply started inside ESP-IDF. You can change its stack allocation using menuconfig: Component config → ESP System Settings -> main task stack size.

Also note that it's more common to drive WS2811 leds and their clones using RMT - ESP-IDF comes with an example driver here.

MarsONTU
Posts: 7
Joined: Tue May 03, 2022 4:14 am

Re: (C) ESP32 SPI Master drive SK68(RGB LED)

Postby MarsONTU » Wed May 04, 2022 10:10 am

ESP_Sprite wrote:
Wed May 04, 2022 8:04 am
Your code always runs in a task, the main task is simply started inside ESP-IDF. You can change its stack allocation using menuconfig: Component config → ESP System Settings -> main task stack size.

Also note that it's more common to drive WS2811 leds and their clones using RMT - ESP-IDF comes with an example driver here.
Thanks again!!!( I'm a beginner in ESP32, even in electronic stuff )

I'll give a try after finishing the SPI way first. When you metion the menuconfig, it seems that there isn't a book or manual Introduce it ( The concrete content ). So the only way is Readme txt in example files?

ESP_Sprite
Posts: 9727
Joined: Thu Nov 26, 2015 4:08 am

Re: (C) ESP32 SPI Master drive SK68(RGB LED)

Postby ESP_Sprite » Wed May 04, 2022 11:42 am

For that driver, yes, the readme and the comments in the headers are what you want. In general, ESP-IDF has pretty good documentation (most of it is also in Chinese if that's easier for you) but I don't think we have a book you can read from back to front to understand the entirety of ESP-IDF... although other people have created pretty good videos, books and articles.

Who is online

Users browsing this forum: Bing [Bot] and 103 guests