// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "esp32-hal-spi.h" #include "esp32-hal.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/semphr.h" #include "esp_attr.h" #include "soc/spi_reg.h" #include "soc/spi_struct.h" #include "soc/io_mux_reg.h" #include "soc/gpio_sig_map.h" #include "soc/rtc.h" #include "driver/periph_ctrl.h" #include "esp_system.h" #ifdef ESP_IDF_VERSION_MAJOR // IDF 4+ #if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4 #include "soc/dport_reg.h" #include "esp32/rom/ets_sys.h" #include "esp32/rom/gpio.h" #include "esp_intr_alloc.h" #elif CONFIG_IDF_TARGET_ESP32S2 #include "soc/dport_reg.h" #include "esp32s2/rom/ets_sys.h" #include "esp32s2/rom/gpio.h" #include "esp_intr_alloc.h" #elif CONFIG_IDF_TARGET_ESP32C3 #include "esp32c3/rom/ets_sys.h" #include "esp32c3/rom/gpio.h" #include "esp_intr_alloc.h" #else #error Target CONFIG_IDF_TARGET is not supported #endif #else // ESP32 Before IDF 4.0 #include "rom/ets_sys.h" #include "rom/gpio.h" #include "esp_intr.h" #endif struct spi_struct_t { spi_dev_t * dev; #if !CONFIG_DISABLE_HAL_LOCKS xSemaphoreHandle lock; #endif uint8_t num; }; #if CONFIG_IDF_TARGET_ESP32S2 // ESP32S2 #define SPI_COUNT (3) #define SPI_CLK_IDX(p) ((p==0)?SPICLK_OUT_MUX_IDX:((p==1)?FSPICLK_OUT_MUX_IDX:((p==2)?SPI3_CLK_OUT_MUX_IDX:0))) #define SPI_MISO_IDX(p) ((p==0)?SPIQ_OUT_IDX:((p==1)?FSPIQ_OUT_IDX:((p==2)?SPI3_Q_OUT_IDX:0))) #define SPI_MOSI_IDX(p) ((p==0)?SPID_IN_IDX:((p==1)?FSPID_IN_IDX:((p==2)?SPI3_D_IN_IDX:0))) #define SPI_SPI_SS_IDX(n) ((n==0)?SPICS0_OUT_IDX:((n==1)?SPICS1_OUT_IDX:0)) #define SPI_HSPI_SS_IDX(n) ((n==0)?SPI3_CS0_OUT_IDX:((n==1)?SPI3_CS1_OUT_IDX:((n==2)?SPI3_CS2_OUT_IDX:SPI3_CS0_OUT_IDX))) #define SPI_FSPI_SS_IDX(n) ((n==0)?FSPICS0_OUT_IDX:((n==1)?FSPICS1_OUT_IDX:((n==2)?FSPICS2_OUT_IDX:FSPICS0_OUT_IDX))) #define SPI_SS_IDX(p, n) ((p==0)?SPI_SPI_SS_IDX(n):((p==1)?SPI_SPI_SS_IDX(n):((p==2)?SPI_HSPI_SS_IDX(n):0))) #define SPI_INTR_SOURCE(u) ((u==0)?ETS_SPI1_INTR_SOURCE:((u==1)?ETS_SPI2_INTR_SOURCE:((u==2)?ETS_SPI3_INTR_SOURCE:0))) #elif CONFIG_IDF_TARGET_ESP32C3 // ESP32S2 #define SPI_COUNT (1) #define SPI_CLK_IDX(p) FSPICLK_OUT_IDX #define SPI_MISO_IDX(p) FSPIQ_OUT_IDX #define SPI_MOSI_IDX(p) FSPID_IN_IDX #define SPI_SPI_SS_IDX(n) ((n==0)?FSPICS0_OUT_IDX:((n==1)?FSPICS1_OUT_IDX:((n==2)?FSPICS2_OUT_IDX:FSPICS0_OUT_IDX))) #define SPI_SS_IDX(p, n) SPI_SPI_SS_IDX(n) #define SPI_INTR_SOURCE(u) ETS_SPI2_INTR_SOURCE #else // ESP32 #define SPI_COUNT (4) #define SPI_CLK_IDX(p) ((p==0)?SPICLK_OUT_IDX:((p==1)?SPICLK_OUT_IDX:((p==2)?HSPICLK_OUT_IDX:((p==3)?VSPICLK_OUT_IDX:0)))) #define SPI_MISO_IDX(p) ((p==0)?SPIQ_OUT_IDX:((p==1)?SPIQ_OUT_IDX:((p==2)?HSPIQ_OUT_IDX:((p==3)?VSPIQ_OUT_IDX:0)))) #define SPI_MOSI_IDX(p) ((p==0)?SPID_IN_IDX:((p==1)?SPID_IN_IDX:((p==2)?HSPID_IN_IDX:((p==3)?VSPID_IN_IDX:0)))) #define SPI_SPI_SS_IDX(n) ((n==0)?SPICS0_OUT_IDX:((n==1)?SPICS1_OUT_IDX:((n==2)?SPICS2_OUT_IDX:SPICS0_OUT_IDX))) #define SPI_HSPI_SS_IDX(n) ((n==0)?HSPICS0_OUT_IDX:((n==1)?HSPICS1_OUT_IDX:((n==2)?HSPICS2_OUT_IDX:HSPICS0_OUT_IDX))) #define SPI_VSPI_SS_IDX(n) ((n==0)?VSPICS0_OUT_IDX:((n==1)?VSPICS1_OUT_IDX:((n==2)?VSPICS2_OUT_IDX:VSPICS0_OUT_IDX))) #define SPI_SS_IDX(p, n) ((p==0)?SPI_SPI_SS_IDX(n):((p==1)?SPI_SPI_SS_IDX(n):((p==2)?SPI_HSPI_SS_IDX(n):((p==3)?SPI_VSPI_SS_IDX(n):0)))) #define SPI_INTR_SOURCE(u) ((u==0)?ETS_SPI0_INTR_SOURCE:((u==1)?ETS_SPI1_INTR_SOURCE:((u==2)?ETS_SPI2_INTR_SOURCE:((p==3)?ETS_SPI3_INTR_SOURCE:0)))) #endif #if CONFIG_DISABLE_HAL_LOCKS #define SPI_MUTEX_LOCK() #define SPI_MUTEX_UNLOCK() static spi_t _spi_bus_array[] = { #if CONFIG_IDF_TARGET_ESP32S2 {(volatile spi_dev_t *)(DR_REG_SPI1_BASE), 0}, {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), 1}, {(volatile spi_dev_t *)(DR_REG_SPI3_BASE), 2} #else {(volatile spi_dev_t *)(DR_REG_SPI0_BASE), 0}, {(volatile spi_dev_t *)(DR_REG_SPI1_BASE), 1}, {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), 2}, {(volatile spi_dev_t *)(DR_REG_SPI3_BASE), 3} #endif }; #else #define SPI_MUTEX_LOCK() do {} while (xSemaphoreTake(spi->lock, portMAX_DELAY) != pdPASS) #define SPI_MUTEX_UNLOCK() xSemaphoreGive(spi->lock) static spi_t _spi_bus_array[] = { #if CONFIG_IDF_TARGET_ESP32S2 {(volatile spi_dev_t *)(DR_REG_SPI1_BASE), NULL, 0}, {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), NULL, 1}, {(volatile spi_dev_t *)(DR_REG_SPI3_BASE), NULL, 2} #elif CONFIG_IDF_TARGET_ESP32C3 {(volatile spi_dev_t *)(&GPSPI2), NULL, FSPI} #else {(volatile spi_dev_t *)(DR_REG_SPI0_BASE), NULL, 0}, {(volatile spi_dev_t *)(DR_REG_SPI1_BASE), NULL, 1}, {(volatile spi_dev_t *)(DR_REG_SPI2_BASE), NULL, 2}, {(volatile spi_dev_t *)(DR_REG_SPI3_BASE), NULL, 3} #endif }; #endif void spiAttachSCK(spi_t * spi, int8_t sck) { if(!spi) { return; } if(sck < 0) { #if CONFIG_IDF_TARGET_ESP32S2 if(spi->num == FSPI) { sck = 36; } else { log_e("HSPI Does not have default pins on ESP32S2!"); return; } #elif CONFIG_IDF_TARGET_ESP32 if(spi->num == HSPI) { sck = 14; } else if(spi->num == VSPI) { sck = 18; } else { sck = 6; } #elif CONFIG_IDF_TARGET_ESP32C3 log_e("SPI Does not have default pins on ESP32C3!"); return; #endif } pinMode(sck, OUTPUT); pinMatrixOutAttach(sck, SPI_CLK_IDX(spi->num), false, false); } void spiAttachMISO(spi_t * spi, int8_t miso) { if(!spi) { return; } if(miso < 0) { #if CONFIG_IDF_TARGET_ESP32S2 if(spi->num == FSPI) { miso = 37; } else { log_e("HSPI Does not have default pins on ESP32S2!"); return; } #elif CONFIG_IDF_TARGET_ESP32 if(spi->num == HSPI) { miso = 12; } else if(spi->num == VSPI) { miso = 19; } else { miso = 7; } #elif CONFIG_IDF_TARGET_ESP32C3 log_e("SPI Does not have default pins on ESP32C3!"); return; #endif } SPI_MUTEX_LOCK(); pinMode(miso, INPUT); pinMatrixInAttach(miso, SPI_MISO_IDX(spi->num), false); SPI_MUTEX_UNLOCK(); } void spiAttachMOSI(spi_t * spi, int8_t mosi) { if(!spi) { return; } if(mosi < 0) { #if CONFIG_IDF_TARGET_ESP32S2 if(spi->num == FSPI) { mosi = 35; } else { log_e("HSPI Does not have default pins on ESP32S2!"); return; } #elif CONFIG_IDF_TARGET_ESP32 if(spi->num == HSPI) { mosi = 13; } else if(spi->num == VSPI) { mosi = 23; } else { mosi = 8; } #elif CONFIG_IDF_TARGET_ESP32C3 log_e("SPI Does not have default pins on ESP32C3!"); return; #endif } pinMode(mosi, OUTPUT); pinMatrixOutAttach(mosi, SPI_MOSI_IDX(spi->num), false, false); } void spiDetachSCK(spi_t * spi, int8_t sck) { if(!spi) { return; } if(sck < 0) { #if CONFIG_IDF_TARGET_ESP32S2 if(spi->num == FSPI) { sck = 36; } else { log_e("HSPI Does not have default pins on ESP32S2!"); return; } #elif CONFIG_IDF_TARGET_ESP32 if(spi->num == HSPI) { sck = 14; } else if(spi->num == VSPI) { sck = 18; } else { sck = 6; } #elif CONFIG_IDF_TARGET_ESP32C3 log_e("SPI Does not have default pins on ESP32C3!"); return; #endif } pinMatrixOutDetach(sck, false, false); pinMode(sck, INPUT); } void spiDetachMISO(spi_t * spi, int8_t miso) { if(!spi) { return; } if(miso < 0) { #if CONFIG_IDF_TARGET_ESP32S2 if(spi->num == FSPI) { miso = 37; } else { log_e("HSPI Does not have default pins on ESP32S2!"); return; } #elif CONFIG_IDF_TARGET_ESP32 if(spi->num == HSPI) { miso = 12; } else if(spi->num == VSPI) { miso = 19; } else { miso = 7; } #elif CONFIG_IDF_TARGET_ESP32C3 log_e("SPI Does not have default pins on ESP32C3!"); return; #endif } pinMatrixInDetach(SPI_MISO_IDX(spi->num), false, false); pinMode(miso, INPUT); } void spiDetachMOSI(spi_t * spi, int8_t mosi) { if(!spi) { return; } if(mosi < 0) { #if CONFIG_IDF_TARGET_ESP32S2 if(spi->num == FSPI) { mosi = 35; } else { log_e("HSPI Does not have default pins on ESP32S2!"); return; } #elif CONFIG_IDF_TARGET_ESP32 if(spi->num == HSPI) { mosi = 13; } else if(spi->num == VSPI) { mosi = 23; } else { mosi = 8; } #elif CONFIG_IDF_TARGET_ESP32C3 log_e("SPI Does not have default pins on ESP32C3!"); return; #endif } pinMatrixOutDetach(mosi, false, false); pinMode(mosi, INPUT); } void spiAttachSS(spi_t * spi, uint8_t cs_num, int8_t ss) { if(!spi) { return; } if(cs_num > 2) { return; } if(ss < 0) { cs_num = 0; #if CONFIG_IDF_TARGET_ESP32S2 if(spi->num == FSPI) { ss = 34; } else { log_e("HSPI Does not have default pins on ESP32S2!"); return; } #elif CONFIG_IDF_TARGET_ESP32 if(spi->num == HSPI) { ss = 15; } else if(spi->num == VSPI) { ss = 5; } else { ss = 11; } #elif CONFIG_IDF_TARGET_ESP32C3 log_e("SPI Does not have default pins on ESP32C3!"); return; #endif } pinMode(ss, OUTPUT); pinMatrixOutAttach(ss, SPI_SS_IDX(spi->num, cs_num), false, false); spiEnableSSPins(spi, (1 << cs_num)); } void spiDetachSS(spi_t * spi, int8_t ss) { if(!spi) { return; } if(ss < 0) { #if CONFIG_IDF_TARGET_ESP32S2 if(spi->num == FSPI) { ss = 34; } else { log_e("HSPI Does not have default pins on ESP32S2!"); return; } #elif CONFIG_IDF_TARGET_ESP32 if(spi->num == HSPI) { ss = 15; } else if(spi->num == VSPI) { ss = 5; } else { ss = 11; } #elif CONFIG_IDF_TARGET_ESP32C3 log_e("SPI Does not have default pins on ESP32C3!"); return; #endif } pinMatrixOutDetach(ss, false, false); pinMode(ss, INPUT); } void spiEnableSSPins(spi_t * spi, uint8_t cs_mask) { if(!spi) { return; } SPI_MUTEX_LOCK(); #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3 spi->dev->misc.val &= ~(cs_mask & SPI_CS_MASK_ALL); #else spi->dev->pin.val &= ~(cs_mask & SPI_CS_MASK_ALL); #endif SPI_MUTEX_UNLOCK(); } void spiDisableSSPins(spi_t * spi, uint8_t cs_mask) { if(!spi) { return; } SPI_MUTEX_LOCK(); #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3 spi->dev->misc.val |= (cs_mask & SPI_CS_MASK_ALL); #else spi->dev->pin.val |= (cs_mask & SPI_CS_MASK_ALL); #endif SPI_MUTEX_UNLOCK(); } void spiSSEnable(spi_t * spi) { if(!spi) { return; } SPI_MUTEX_LOCK(); spi->dev->user.cs_setup = 1; spi->dev->user.cs_hold = 1; SPI_MUTEX_UNLOCK(); } void spiSSDisable(spi_t * spi) { if(!spi) { return; } SPI_MUTEX_LOCK(); spi->dev->user.cs_setup = 0; spi->dev->user.cs_hold = 0; SPI_MUTEX_UNLOCK(); } void spiSSSet(spi_t * spi) { if(!spi) { return; } SPI_MUTEX_LOCK(); #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3 spi->dev->misc.cs_keep_active = 1; #else spi->dev->pin.cs_keep_active = 1; #endif SPI_MUTEX_UNLOCK(); } void spiSSClear(spi_t * spi) { if(!spi) { return; } SPI_MUTEX_LOCK(); #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3 spi->dev->misc.cs_keep_active = 0; #else spi->dev->pin.cs_keep_active = 0; #endif SPI_MUTEX_UNLOCK(); } uint32_t spiGetClockDiv(spi_t * spi) { if(!spi) { return 0; } return spi->dev->clock.val; } void spiSetClockDiv(spi_t * spi, uint32_t clockDiv) { if(!spi) { return; } SPI_MUTEX_LOCK(); spi->dev->clock.val = clockDiv; SPI_MUTEX_UNLOCK(); } uint8_t spiGetDataMode(spi_t * spi) { if(!spi) { return 0; } #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3 bool idleEdge = spi->dev->misc.ck_idle_edge; #else bool idleEdge = spi->dev->pin.ck_idle_edge; #endif bool outEdge = spi->dev->user.ck_out_edge; if(idleEdge) { if(outEdge) { return SPI_MODE2; } return SPI_MODE3; } if(outEdge) { return SPI_MODE1; } return SPI_MODE0; } void spiSetDataMode(spi_t * spi, uint8_t dataMode) { if(!spi) { return; } SPI_MUTEX_LOCK(); switch (dataMode) { case SPI_MODE1: #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3 spi->dev->misc.ck_idle_edge = 0; #else spi->dev->pin.ck_idle_edge = 0; #endif spi->dev->user.ck_out_edge = 1; break; case SPI_MODE2: #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3 spi->dev->misc.ck_idle_edge = 1; #else spi->dev->pin.ck_idle_edge = 1; #endif spi->dev->user.ck_out_edge = 1; break; case SPI_MODE3: #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3 spi->dev->misc.ck_idle_edge = 1; #else spi->dev->pin.ck_idle_edge = 1; #endif spi->dev->user.ck_out_edge = 0; break; case SPI_MODE0: default: #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3 spi->dev->misc.ck_idle_edge = 0; #else spi->dev->pin.ck_idle_edge = 0; #endif spi->dev->user.ck_out_edge = 0; break; } SPI_MUTEX_UNLOCK(); } uint8_t spiGetBitOrder(spi_t * spi) { if(!spi) { return 0; } return (spi->dev->ctrl.wr_bit_order | spi->dev->ctrl.rd_bit_order) == 0; } void spiSetBitOrder(spi_t * spi, uint8_t bitOrder) { if(!spi) { return; } SPI_MUTEX_LOCK(); if (SPI_MSBFIRST == bitOrder) { spi->dev->ctrl.wr_bit_order = 0; spi->dev->ctrl.rd_bit_order = 0; } else if (SPI_LSBFIRST == bitOrder) { spi->dev->ctrl.wr_bit_order = 1; spi->dev->ctrl.rd_bit_order = 1; } SPI_MUTEX_UNLOCK(); } static void _on_apb_change(void * arg, apb_change_ev_t ev_type, uint32_t old_apb, uint32_t new_apb) { spi_t * spi = (spi_t *)arg; if(ev_type == APB_BEFORE_CHANGE){ SPI_MUTEX_LOCK(); while(spi->dev->cmd.usr); } else { spi->dev->clock.val = spiFrequencyToClockDiv(old_apb / ((spi->dev->clock.clkdiv_pre + 1) * (spi->dev->clock.clkcnt_n + 1))); SPI_MUTEX_UNLOCK(); } } static void spiInitBus(spi_t * spi) { #ifndef CONFIG_IDF_TARGET_ESP32C3 spi->dev->slave.trans_done = 0; #endif spi->dev->slave.val = 0; #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3 spi->dev->misc.val = 0; #else spi->dev->pin.val = 0; #endif spi->dev->user.val = 0; spi->dev->user1.val = 0; spi->dev->ctrl.val = 0; #ifndef CONFIG_IDF_TARGET_ESP32C3 spi->dev->ctrl1.val = 0; spi->dev->ctrl2.val = 0; #else spi->dev->clk_gate.val = 0; spi->dev->dma_conf.val = 0; spi->dev->dma_conf.rx_afifo_rst = 1; spi->dev->dma_conf.buf_afifo_rst = 1; #endif spi->dev->clock.val = 0; } void spiStopBus(spi_t * spi) { if(!spi) { return; } removeApbChangeCallback(spi, _on_apb_change); SPI_MUTEX_LOCK(); spiInitBus(spi); SPI_MUTEX_UNLOCK(); } spi_t * spiStartBus(uint8_t spi_num, uint32_t clockDiv, uint8_t dataMode, uint8_t bitOrder) { if(spi_num >= SPI_COUNT){ return NULL; } spi_t * spi = &_spi_bus_array[spi_num]; #if !CONFIG_DISABLE_HAL_LOCKS if(spi->lock == NULL){ spi->lock = xSemaphoreCreateMutex(); if(spi->lock == NULL) { return NULL; } } #endif #if CONFIG_IDF_TARGET_ESP32S2 if(spi_num == FSPI) { DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI2_CLK_EN); DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI2_RST); } else if(spi_num == HSPI) { DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI3_CLK_EN); DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI3_RST); } else { DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI01_CLK_EN); DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI01_RST); } #elif CONFIG_IDF_TARGET_ESP32 if(spi_num == HSPI) { DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI2_CLK_EN); DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI2_RST); } else if(spi_num == VSPI) { DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI3_CLK_EN); DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI3_RST); } else { DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI01_CLK_EN); DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI01_RST); } #elif CONFIG_IDF_TARGET_ESP32C3 periph_module_reset( PERIPH_SPI2_MODULE ); periph_module_enable( PERIPH_SPI2_MODULE ); #endif SPI_MUTEX_LOCK(); spiInitBus(spi); #if CONFIG_IDF_TARGET_ESP32C3 spi->dev->clk_gate.clk_en = 1; spi->dev->clk_gate.mst_clk_sel = 1; spi->dev->clk_gate.mst_clk_active = 1; spi->dev->dma_conf.tx_seg_trans_clr_en = 1; spi->dev->dma_conf.rx_seg_trans_clr_en = 1; spi->dev->dma_conf.dma_seg_trans_en = 0; #endif spi->dev->user.usr_mosi = 1; spi->dev->user.usr_miso = 1; spi->dev->user.doutdin = 1; int i; for(i=0; i<16; i++) { spi->dev->data_buf[i] = 0x00000000; } SPI_MUTEX_UNLOCK(); spiSetDataMode(spi, dataMode); spiSetBitOrder(spi, bitOrder); spiSetClockDiv(spi, clockDiv); addApbChangeCallback(spi, _on_apb_change); return spi; } void spiWaitReady(spi_t * spi) { if(!spi) { return; } while(spi->dev->cmd.usr); } #if CONFIG_IDF_TARGET_ESP32S2 #define usr_mosi_dbitlen usr_mosi_bit_len #define usr_miso_dbitlen usr_miso_bit_len #elif CONFIG_IDF_TARGET_ESP32C3 #define usr_mosi_dbitlen ms_data_bitlen #define usr_miso_dbitlen ms_data_bitlen #define mosi_dlen ms_dlen #define miso_dlen ms_dlen #endif void spiWrite(spi_t * spi, const uint32_t *data, uint8_t len) { if(!spi) { return; } int i; if(len > 16) { len = 16; } SPI_MUTEX_LOCK(); spi->dev->mosi_dlen.usr_mosi_dbitlen = (len * 32) - 1; #ifndef CONFIG_IDF_TARGET_ESP32C3 spi->dev->miso_dlen.usr_miso_dbitlen = 0; #endif for(i=0; idev->data_buf[i] = data[i]; } #if CONFIG_IDF_TARGET_ESP32C3 spi->dev->cmd.update = 1; while (spi->dev->cmd.update); #endif spi->dev->cmd.usr = 1; while(spi->dev->cmd.usr); SPI_MUTEX_UNLOCK(); } void spiTransfer(spi_t * spi, uint32_t *data, uint8_t len) { if(!spi) { return; } int i; if(len > 16) { len = 16; } SPI_MUTEX_LOCK(); spi->dev->mosi_dlen.usr_mosi_dbitlen = (len * 32) - 1; spi->dev->miso_dlen.usr_miso_dbitlen = (len * 32) - 1; for(i=0; idev->data_buf[i] = data[i]; } #if CONFIG_IDF_TARGET_ESP32C3 spi->dev->cmd.update = 1; while (spi->dev->cmd.update); #endif spi->dev->cmd.usr = 1; while(spi->dev->cmd.usr); for(i=0; idev->data_buf[i]; } SPI_MUTEX_UNLOCK(); } void spiWriteByte(spi_t * spi, uint8_t data) { if(!spi) { return; } SPI_MUTEX_LOCK(); spi->dev->mosi_dlen.usr_mosi_dbitlen = 7; #ifndef CONFIG_IDF_TARGET_ESP32C3 spi->dev->miso_dlen.usr_miso_dbitlen = 0; #endif spi->dev->data_buf[0] = data; #if CONFIG_IDF_TARGET_ESP32C3 spi->dev->cmd.update = 1; while (spi->dev->cmd.update); #endif spi->dev->cmd.usr = 1; while(spi->dev->cmd.usr); SPI_MUTEX_UNLOCK(); } uint8_t spiTransferByte(spi_t * spi, uint8_t data) { if(!spi) { return 0; } SPI_MUTEX_LOCK(); spi->dev->mosi_dlen.usr_mosi_dbitlen = 7; spi->dev->miso_dlen.usr_miso_dbitlen = 7; spi->dev->data_buf[0] = data; #if CONFIG_IDF_TARGET_ESP32C3 spi->dev->cmd.update = 1; while (spi->dev->cmd.update); #endif spi->dev->cmd.usr = 1; while(spi->dev->cmd.usr); data = spi->dev->data_buf[0] & 0xFF; SPI_MUTEX_UNLOCK(); return data; } static uint32_t __spiTranslate32(uint32_t data) { union { uint32_t l; uint8_t b[4]; } out; out.l = data; return out.b[3] | (out.b[2] << 8) | (out.b[1] << 16) | (out.b[0] << 24); } void spiWriteWord(spi_t * spi, uint16_t data) { if(!spi) { return; } if(!spi->dev->ctrl.wr_bit_order){ data = (data >> 8) | (data << 8); } SPI_MUTEX_LOCK(); spi->dev->mosi_dlen.usr_mosi_dbitlen = 15; #ifndef CONFIG_IDF_TARGET_ESP32C3 spi->dev->miso_dlen.usr_miso_dbitlen = 0; #endif spi->dev->data_buf[0] = data; #if CONFIG_IDF_TARGET_ESP32C3 spi->dev->cmd.update = 1; while (spi->dev->cmd.update); #endif spi->dev->cmd.usr = 1; while(spi->dev->cmd.usr); SPI_MUTEX_UNLOCK(); } uint16_t spiTransferWord(spi_t * spi, uint16_t data) { if(!spi) { return 0; } if(!spi->dev->ctrl.wr_bit_order){ data = (data >> 8) | (data << 8); } SPI_MUTEX_LOCK(); spi->dev->mosi_dlen.usr_mosi_dbitlen = 15; spi->dev->miso_dlen.usr_miso_dbitlen = 15; spi->dev->data_buf[0] = data; #if CONFIG_IDF_TARGET_ESP32C3 spi->dev->cmd.update = 1; while (spi->dev->cmd.update); #endif spi->dev->cmd.usr = 1; while(spi->dev->cmd.usr); data = spi->dev->data_buf[0]; SPI_MUTEX_UNLOCK(); if(!spi->dev->ctrl.rd_bit_order){ data = (data >> 8) | (data << 8); } return data; } void spiWriteLong(spi_t * spi, uint32_t data) { if(!spi) { return; } if(!spi->dev->ctrl.wr_bit_order){ data = __spiTranslate32(data); } SPI_MUTEX_LOCK(); spi->dev->mosi_dlen.usr_mosi_dbitlen = 31; #ifndef CONFIG_IDF_TARGET_ESP32C3 spi->dev->miso_dlen.usr_miso_dbitlen = 0; #endif spi->dev->data_buf[0] = data; #if CONFIG_IDF_TARGET_ESP32C3 spi->dev->cmd.update = 1; while (spi->dev->cmd.update); #endif spi->dev->cmd.usr = 1; while(spi->dev->cmd.usr); SPI_MUTEX_UNLOCK(); } uint32_t spiTransferLong(spi_t * spi, uint32_t data) { if(!spi) { return 0; } if(!spi->dev->ctrl.wr_bit_order){ data = __spiTranslate32(data); } SPI_MUTEX_LOCK(); spi->dev->mosi_dlen.usr_mosi_dbitlen = 31; spi->dev->miso_dlen.usr_miso_dbitlen = 31; spi->dev->data_buf[0] = data; #if CONFIG_IDF_TARGET_ESP32C3 spi->dev->cmd.update = 1; while (spi->dev->cmd.update); #endif spi->dev->cmd.usr = 1; while(spi->dev->cmd.usr); data = spi->dev->data_buf[0]; SPI_MUTEX_UNLOCK(); if(!spi->dev->ctrl.rd_bit_order){ data = __spiTranslate32(data); } return data; } static void __spiTransferBytes(spi_t * spi, const uint8_t * data, uint8_t * out, uint32_t bytes) { if(!spi) { return; } int i; if(bytes > 64) { bytes = 64; } uint32_t words = (bytes + 3) / 4;//16 max uint32_t wordsBuf[16] = {0,}; uint8_t * bytesBuf = (uint8_t *) wordsBuf; if(data) { memcpy(bytesBuf, data, bytes);//copy data to buffer } else { memset(bytesBuf, 0xFF, bytes); } spi->dev->mosi_dlen.usr_mosi_dbitlen = ((bytes * 8) - 1); spi->dev->miso_dlen.usr_miso_dbitlen = ((bytes * 8) - 1); for(i=0; idev->data_buf[i] = wordsBuf[i]; //copy buffer to spi fifo } #if CONFIG_IDF_TARGET_ESP32C3 spi->dev->cmd.update = 1; while (spi->dev->cmd.update); #endif spi->dev->cmd.usr = 1; while(spi->dev->cmd.usr); if(out) { for(i=0; idev->data_buf[i];//copy spi fifo to buffer } memcpy(out, bytesBuf, bytes);//copy buffer to output } } void spiTransferBytes(spi_t * spi, const uint8_t * data, uint8_t * out, uint32_t size) { if(!spi) { return; } SPI_MUTEX_LOCK(); while(size) { if(size > 64) { __spiTransferBytes(spi, data, out, 64); size -= 64; if(data) { data += 64; } if(out) { out += 64; } } else { __spiTransferBytes(spi, data, out, size); size = 0; } } SPI_MUTEX_UNLOCK(); } void spiTransferBits(spi_t * spi, uint32_t data, uint32_t * out, uint8_t bits) { if(!spi) { return; } SPI_MUTEX_LOCK(); spiTransferBitsNL(spi, data, out, bits); SPI_MUTEX_UNLOCK(); } /* * Manual Lock Management * */ #define MSB_32_SET(var, val) { uint8_t * d = (uint8_t *)&(val); (var) = d[3] | (d[2] << 8) | (d[1] << 16) | (d[0] << 24); } #define MSB_24_SET(var, val) { uint8_t * d = (uint8_t *)&(val); (var) = d[2] | (d[1] << 8) | (d[0] << 16); } #define MSB_16_SET(var, val) { (var) = (((val) & 0xFF00) >> 8) | (((val) & 0xFF) << 8); } #define MSB_PIX_SET(var, val) { uint8_t * d = (uint8_t *)&(val); (var) = d[1] | (d[0] << 8) | (d[3] << 16) | (d[2] << 24); } void spiTransaction(spi_t * spi, uint32_t clockDiv, uint8_t dataMode, uint8_t bitOrder) { if(!spi) { return; } SPI_MUTEX_LOCK(); spi->dev->clock.val = clockDiv; switch (dataMode) { case SPI_MODE1: #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3 spi->dev->misc.ck_idle_edge = 0; #else spi->dev->pin.ck_idle_edge = 0; #endif spi->dev->user.ck_out_edge = 1; break; case SPI_MODE2: #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3 spi->dev->misc.ck_idle_edge = 1; #else spi->dev->pin.ck_idle_edge = 1; #endif spi->dev->user.ck_out_edge = 1; break; case SPI_MODE3: #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3 spi->dev->misc.ck_idle_edge = 1; #else spi->dev->pin.ck_idle_edge = 1; #endif spi->dev->user.ck_out_edge = 0; break; case SPI_MODE0: default: #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32C3 spi->dev->misc.ck_idle_edge = 0; #else spi->dev->pin.ck_idle_edge = 0; #endif spi->dev->user.ck_out_edge = 0; break; } if (SPI_MSBFIRST == bitOrder) { spi->dev->ctrl.wr_bit_order = 0; spi->dev->ctrl.rd_bit_order = 0; } else if (SPI_LSBFIRST == bitOrder) { spi->dev->ctrl.wr_bit_order = 1; spi->dev->ctrl.rd_bit_order = 1; } } void spiSimpleTransaction(spi_t * spi) { if(!spi) { return; } SPI_MUTEX_LOCK(); } void spiEndTransaction(spi_t * spi) { if(!spi) { return; } SPI_MUTEX_UNLOCK(); } void ARDUINO_ISR_ATTR spiWriteByteNL(spi_t * spi, uint8_t data) { if(!spi) { return; } spi->dev->mosi_dlen.usr_mosi_dbitlen = 7; #ifndef CONFIG_IDF_TARGET_ESP32C3 spi->dev->miso_dlen.usr_miso_dbitlen = 0; #endif spi->dev->data_buf[0] = data; #if CONFIG_IDF_TARGET_ESP32C3 spi->dev->cmd.update = 1; while (spi->dev->cmd.update); #endif spi->dev->cmd.usr = 1; while(spi->dev->cmd.usr); } uint8_t spiTransferByteNL(spi_t * spi, uint8_t data) { if(!spi) { return 0; } spi->dev->mosi_dlen.usr_mosi_dbitlen = 7; spi->dev->miso_dlen.usr_miso_dbitlen = 7; spi->dev->data_buf[0] = data; #if CONFIG_IDF_TARGET_ESP32C3 spi->dev->cmd.update = 1; while (spi->dev->cmd.update); #endif spi->dev->cmd.usr = 1; while(spi->dev->cmd.usr); data = spi->dev->data_buf[0] & 0xFF; return data; } void ARDUINO_ISR_ATTR spiWriteShortNL(spi_t * spi, uint16_t data) { if(!spi) { return; } if(!spi->dev->ctrl.wr_bit_order){ MSB_16_SET(data, data); } spi->dev->mosi_dlen.usr_mosi_dbitlen = 15; #ifndef CONFIG_IDF_TARGET_ESP32C3 spi->dev->miso_dlen.usr_miso_dbitlen = 0; #endif spi->dev->data_buf[0] = data; #if CONFIG_IDF_TARGET_ESP32C3 spi->dev->cmd.update = 1; while (spi->dev->cmd.update); #endif spi->dev->cmd.usr = 1; while(spi->dev->cmd.usr); } uint16_t spiTransferShortNL(spi_t * spi, uint16_t data) { if(!spi) { return 0; } if(!spi->dev->ctrl.wr_bit_order){ MSB_16_SET(data, data); } spi->dev->mosi_dlen.usr_mosi_dbitlen = 15; spi->dev->miso_dlen.usr_miso_dbitlen = 15; spi->dev->data_buf[0] = data; #if CONFIG_IDF_TARGET_ESP32C3 spi->dev->cmd.update = 1; while (spi->dev->cmd.update); #endif spi->dev->cmd.usr = 1; while(spi->dev->cmd.usr); data = spi->dev->data_buf[0] & 0xFFFF; if(!spi->dev->ctrl.rd_bit_order){ MSB_16_SET(data, data); } return data; } void ARDUINO_ISR_ATTR spiWriteLongNL(spi_t * spi, uint32_t data) { if(!spi) { return; } if(!spi->dev->ctrl.wr_bit_order){ MSB_32_SET(data, data); } spi->dev->mosi_dlen.usr_mosi_dbitlen = 31; #ifndef CONFIG_IDF_TARGET_ESP32C3 spi->dev->miso_dlen.usr_miso_dbitlen = 0; #endif spi->dev->data_buf[0] = data; #if CONFIG_IDF_TARGET_ESP32C3 spi->dev->cmd.update = 1; while (spi->dev->cmd.update); #endif spi->dev->cmd.usr = 1; while(spi->dev->cmd.usr); } uint32_t spiTransferLongNL(spi_t * spi, uint32_t data) { if(!spi) { return 0; } if(!spi->dev->ctrl.wr_bit_order){ MSB_32_SET(data, data); } spi->dev->mosi_dlen.usr_mosi_dbitlen = 31; spi->dev->miso_dlen.usr_miso_dbitlen = 31; spi->dev->data_buf[0] = data; #if CONFIG_IDF_TARGET_ESP32C3 spi->dev->cmd.update = 1; while (spi->dev->cmd.update); #endif spi->dev->cmd.usr = 1; while(spi->dev->cmd.usr); data = spi->dev->data_buf[0]; if(!spi->dev->ctrl.rd_bit_order){ MSB_32_SET(data, data); } return data; } void spiWriteNL(spi_t * spi, const void * data_in, uint32_t len){ if(!spi) { return; } size_t longs = len >> 2; if(len & 3){ longs++; } uint32_t * data = (uint32_t*)data_in; size_t c_len = 0, c_longs = 0; while(len){ c_len = (len>64)?64:len; c_longs = (longs > 16)?16:longs; spi->dev->mosi_dlen.usr_mosi_dbitlen = (c_len*8)-1; #ifndef CONFIG_IDF_TARGET_ESP32C3 spi->dev->miso_dlen.usr_miso_dbitlen = 0; #endif for (int i=0; idev->data_buf[i] = data[i]; } #if CONFIG_IDF_TARGET_ESP32C3 spi->dev->cmd.update = 1; while (spi->dev->cmd.update); #endif spi->dev->cmd.usr = 1; while(spi->dev->cmd.usr); data += c_longs; longs -= c_longs; len -= c_len; } } void spiTransferBytesNL(spi_t * spi, const void * data_in, uint8_t * data_out, uint32_t len){ if(!spi) { return; } size_t longs = len >> 2; if(len & 3){ longs++; } uint32_t * data = (uint32_t*)data_in; uint32_t * result = (uint32_t*)data_out; size_t c_len = 0, c_longs = 0; while(len){ c_len = (len>64)?64:len; c_longs = (longs > 16)?16:longs; spi->dev->mosi_dlen.usr_mosi_dbitlen = (c_len*8)-1; spi->dev->miso_dlen.usr_miso_dbitlen = (c_len*8)-1; if(data){ for (int i=0; idev->data_buf[i] = data[i]; } } else { for (int i=0; idev->data_buf[i] = 0xFFFFFFFF; } } #if CONFIG_IDF_TARGET_ESP32C3 spi->dev->cmd.update = 1; while (spi->dev->cmd.update); #endif spi->dev->cmd.usr = 1; while(spi->dev->cmd.usr); if(result){ if(c_len & 3){ for (int i=0; i<(c_longs-1); i++) { result[i] = spi->dev->data_buf[i]; } uint32_t last_data = spi->dev->data_buf[c_longs-1]; uint8_t * last_out8 = (uint8_t *)&result[c_longs-1]; uint8_t * last_data8 = (uint8_t *)&last_data; for (int i=0; i<(c_len & 3); i++) { last_out8[i] = last_data8[i]; } } else { for (int i=0; idev->data_buf[i]; } } } if(data){ data += c_longs; } if(result){ result += c_longs; } longs -= c_longs; len -= c_len; } } void spiTransferBitsNL(spi_t * spi, uint32_t data, uint32_t * out, uint8_t bits) { if(!spi) { return; } if(bits > 32) { bits = 32; } uint32_t bytes = (bits + 7) / 8;//64 max uint32_t mask = (((uint64_t)1 << bits) - 1) & 0xFFFFFFFF; data = data & mask; if(!spi->dev->ctrl.wr_bit_order){ if(bytes == 2) { MSB_16_SET(data, data); } else if(bytes == 3) { MSB_24_SET(data, data); } else { MSB_32_SET(data, data); } } spi->dev->mosi_dlen.usr_mosi_dbitlen = (bits - 1); spi->dev->miso_dlen.usr_miso_dbitlen = (bits - 1); spi->dev->data_buf[0] = data; #if CONFIG_IDF_TARGET_ESP32C3 spi->dev->cmd.update = 1; while (spi->dev->cmd.update); #endif spi->dev->cmd.usr = 1; while(spi->dev->cmd.usr); data = spi->dev->data_buf[0]; if(out) { *out = data; if(!spi->dev->ctrl.rd_bit_order){ if(bytes == 2) { MSB_16_SET(*out, data); } else if(bytes == 3) { MSB_24_SET(*out, data); } else { MSB_32_SET(*out, data); } } } } void ARDUINO_ISR_ATTR spiWritePixelsNL(spi_t * spi, const void * data_in, uint32_t len){ size_t longs = len >> 2; if(len & 3){ longs++; } bool msb = !spi->dev->ctrl.wr_bit_order; uint32_t * data = (uint32_t*)data_in; size_t c_len = 0, c_longs = 0, l_bytes = 0; while(len){ c_len = (len>64)?64:len; c_longs = (longs > 16)?16:longs; l_bytes = (c_len & 3); spi->dev->mosi_dlen.usr_mosi_dbitlen = (c_len*8)-1; #ifndef CONFIG_IDF_TARGET_ESP32C3 spi->dev->miso_dlen.usr_miso_dbitlen = 0; #endif for (int i=0; idev->data_buf[i], data[i]); } else { spi->dev->data_buf[i] = data[i] & 0xFF; } } else { MSB_PIX_SET(spi->dev->data_buf[i], data[i]); } } else { spi->dev->data_buf[i] = data[i]; } } #if CONFIG_IDF_TARGET_ESP32C3 spi->dev->cmd.update = 1; while (spi->dev->cmd.update); #endif spi->dev->cmd.usr = 1; while(spi->dev->cmd.usr); data += c_longs; longs -= c_longs; len -= c_len; } } /* * Clock Calculators * * */ typedef union { uint32_t value; struct { uint32_t clkcnt_l: 6; /*it must be equal to spi_clkcnt_N.*/ uint32_t clkcnt_h: 6; /*it must be floor((spi_clkcnt_N+1)/2-1).*/ uint32_t clkcnt_n: 6; /*it is the divider of spi_clk. So spi_clk frequency is system/(spi_clkdiv_pre+1)/(spi_clkcnt_N+1)*/ #if CONFIG_IDF_TARGET_ESP32C3 uint32_t clkdiv_pre: 4; /*it is pre-divider of spi_clk.*/ uint32_t reserved: 9; /*reserved*/ #else uint32_t clkdiv_pre: 13; /*it is pre-divider of spi_clk.*/ #endif uint32_t clk_equ_sysclk: 1; /*1: spi_clk is eqaul to system 0: spi_clk is divided from system clock.*/ }; } spiClk_t; #define ClkRegToFreq(reg) (apb_freq / (((reg)->clkdiv_pre + 1) * ((reg)->clkcnt_n + 1))) uint32_t spiClockDivToFrequency(uint32_t clockDiv) { uint32_t apb_freq = getApbFrequency(); spiClk_t reg = { clockDiv }; return ClkRegToFreq(®); } uint32_t spiFrequencyToClockDiv(uint32_t freq) { uint32_t apb_freq = getApbFrequency(); if(freq >= apb_freq) { return SPI_CLK_EQU_SYSCLK; } const spiClk_t minFreqReg = { 0x7FFFF000 }; uint32_t minFreq = ClkRegToFreq((spiClk_t*) &minFreqReg); if(freq < minFreq) { return minFreqReg.value; } uint8_t calN = 1; spiClk_t bestReg = { 0 }; int32_t bestFreq = 0; while(calN <= 0x3F) { spiClk_t reg = { 0 }; int32_t calFreq; int32_t calPre; int8_t calPreVari = -2; reg.clkcnt_n = calN; while(calPreVari++ <= 1) { calPre = (((apb_freq / (reg.clkcnt_n + 1)) / freq) - 1) + calPreVari; #if CONFIG_IDF_TARGET_ESP32C3 if(calPre > 0xF) { reg.clkdiv_pre = 0xF; #else if(calPre > 0x1FFF) { reg.clkdiv_pre = 0x1FFF; #endif } else if(calPre <= 0) { reg.clkdiv_pre = 0; } else { reg.clkdiv_pre = calPre; } reg.clkcnt_l = ((reg.clkcnt_n + 1) / 2); calFreq = ClkRegToFreq(®); if(calFreq == (int32_t) freq) { memcpy(&bestReg, ®, sizeof(bestReg)); break; } else if(calFreq < (int32_t) freq) { if(abs(freq - calFreq) < abs(freq - bestFreq)) { bestFreq = calFreq; memcpy(&bestReg, ®, sizeof(bestReg)); } } } if(calFreq == (int32_t) freq) { break; } calN++; } return bestReg.value; }