Skip to content

SPI receive by DMA #2086

@techtoys

Description

@techtoys

Hardware:

Board: ESP32 Pico Kit
Core Installation/update date: ARDUINO_ESP32_RELEASE "1_0_0"
IDE name: Arduino IDE
Flash Frequency: 40Mhz
PSRAM enabled: no
Upload Speed: 115200
Computer OS: Windows 7

Description:

Not able to receive the full 4 bytes SPI value from MISO. Only the first byte received properly into rx_data[] somehow, although it shows from a logic analyzer that the correct return values are present from electronic signal. It turns out that rx_data[0] = 0x42 is correct, rx_data[1:3]=0x00 which is not correct. rx_data[1] should be 0x7C as indicated by a logic analyzer.

#ifndef BT815_h
#define BT815_h

#include <Arduino.h>
#include "driver/spi_master.h"

// Attaching VSPI module to BT815
#define PIN_NUM_MISO 19
#define PIN_NUM_MOSI 23
#define PIN_NUM_CLK 18
#define PIN_NUM_CS 5
#define PIN_NUM_PD 22 //PD pin ofr BT815

// BT815 Memory Commands - use with hal_bt815memWritexx and hal_bt815memReadxx
#define MEM_WRITE 0x80 // BT815 Host Memory Write
#define MEM_READ 0x00 // BT815 Host Memory Read

// BT815 Chip Commands - use with cmdWrite
#define BT815_ACTIVE 0x00 // Initializes BT815
#define BT815_STANDBY 0x41 // Place BT815 in Standby (clk running)
#define BT815_SLEEP 0x42 // Place BT815 in Sleep (clk off)
#define BT815_PWRDOWN 0x50 // Place BT815 in Power Down (core off)
#define BT815_CLKEXT 0x44 // Select external clock source
#define BT815_CLKINT 0x48 // Select internal clock source
#define BT815_CLKSEL 0x61 // Select PLL mulitplier with second byte (param), consult data sheet for this
#define BT815_CLK60M 0x62 // Select 60MHz PLL with param set 0 for compatibility with FT800/FT801
#define BT815_CORERST 0x68 // Reset core - all registers default
#define BT815_PINDRIVE 0x70 // Set drive strength for various pins (consult data sheet)

#define REG_ID 0x302000UL

class BT815Class {
public:
BT815Class();
void memWriteN(uint32_t ftAddress, const uint8_t *ftData8, uint32_t len);
void memWrite8(uint32_t ftAddress, uint8_t ftData8);
void memWrite16(uint32_t ftAddress, uint16_t ftData16);
void memWrite32(uint32_t ftAddress, uint32_t ftData32);
void cmdWrite(uint8_t ftCommand, uint8_t param=0x00);
void memReadN(uint32_t ftAddress, uint8_t *ftData8, uint32_t len);
uint8_t memRead8(uint32_t ftAddress);
uint16_t memRead16(uint32_t ftAddress);
uint32_t memRead32(uint32_t ftAddress);
void hwReset(void);
private:
spi_device_handle_t bt815;
};

BT815Class::BT815Class()
{
esp_err_t ret;
spi_bus_config_t buscfg;

    buscfg.miso_io_num=PIN_NUM_MISO;
    buscfg.mosi_io_num=PIN_NUM_MOSI;
    buscfg.sclk_io_num=PIN_NUM_CLK;
    buscfg.quadwp_io_num=-1;
    buscfg.quadhd_io_num=-1;
    buscfg.max_transfer_sz=0; //default to 4092 if 0

spi_device_interface_config_t devcfg;

    devcfg.clock_speed_hz=SPI_MASTER_FREQ_26M;    //SPI_MASTER_FREQ_26M defined in spi_master.h
    devcfg.mode=0;                                //SPI mode 0
    devcfg.spics_io_num=PIN_NUM_CS;               //CS pin
    devcfg.queue_size=7;                          //We want to be able to queue 7 transactions at a time
    devcfg.address_bits=24;                       //24 bits for address
    
//Initialize the SPI bus
ret = spi_bus_initialize(VSPI_HOST, &buscfg, 1);    //DMA channel 1
ESP_ERROR_CHECK(ret);
//Attach BT815 to VSPI host of ESP32 by spi_bus_add_device()
ret = spi_bus_add_device(VSPI_HOST, &devcfg, &bt815);
ESP_ERROR_CHECK(ret);   

 pinMode(PIN_NUM_PD,OUTPUT);
 digitalWrite(PIN_NUM_PD,HIGH);

}

void BT815Class::memWriteN(uint32_t ftAddress, const uint8_t ftData8, uint32_t len)
{
esp_err_t ret;
spi_transaction_t t;
if(len==0) return;
memset(&t, 0, sizeof(t)); //Zero out the transaction
t.length=8
len; //length in bits therefore *8
t.tx_buffer=ftData8;
t.addr = ftAddress|(MEM_WRITE<<16); //devcfg.address_bits = 24; in class constructor
ret = spi_device_transmit(bt815, &t); //Transmit!
assert(ret==ESP_OK); //Should have had no issues.
}

void BT815Class::memWrite8(uint32_t ftAddress, uint8_t ftData8)
{
memWriteN(ftAddress, &ftData8, 1);
}

void BT815Class::memWrite16(uint32_t ftAddress, uint16_t ftData16)
{
memWriteN(ftAddress, (uint8_t *)&ftData16, 2); //send low byte first, this verified with a logic analyzer to be OK
}

void BT815Class::memWrite32(uint32_t ftAddress, uint32_t ftData32)
{
memWriteN(ftAddress, (uint8_t *)&ftData32, 4); //send low byte first, this verified with a logic analyzer to be OK
}

void BT815Class::cmdWrite(uint8_t ftCommand, uint8_t param)
{
esp_err_t ret;
spi_transaction_t t;

memset(&t, 0, sizeof(t));
t.length = 0;
t.addr = (uint32_t)ftCommand<<16 | (uint32_t)param<<8;

ret = spi_device_transmit(bt815, &t);

assert(ret==ESP_OK);
}

void BT815Class::memReadN(uint32_t ftAddress, uint8_t ftData8, uint32_t len)
{
if(len==0) return;
uint8_t dummy = 0xff; //dummy byte assigned an arbitrary value here, it can be any value.
esp_err_t ret;
spi_transaction_t t;
memset(&t, 0, sizeof(t)); //zero out the transaction
t.length = 8
(len); //length in bits therefore *8
t.rxlength = t.length;
t.tx_buffer = (uint8_t *) &dummy;
t.addr = ftAddress; //devcfg.address_bits = 24 in class constructor
t.flags = SPI_TRANS_USE_RXDATA; //data sent direct to rx_data[4]
ret = spi_device_transmit(bt815, &t); //transmit & receive in full duplex

assert(ret==ESP_OK);                          //Should have had no issues. 
for(int i=0; i<len; i++)
{
  *ftData8++ = t.rx_data[i];  
}

}

uint8_t BT815Class::memRead8(uint32_t ftAddress)
{
uint8_t _ret;
memReadN(ftAddress, (uint8_t *)&_ret, 1);

return _ret;
}

//@brief Hardware reset BT815 with PD pin driven low for 20ms
void BT815Class::hwReset(void)
{
digitalWrite(PIN_NUM_PD, LOW);
vTaskDelay((TickType_t)20/portTICK_PERIOD_MS); //hold for 20ms
digitalWrite(PIN_NUM_PD, HIGH);
vTaskDelay((TickType_t)20/portTICK_PERIOD_MS); //hold for 20ms before sending any command
}

#endif //BT815_h
/** EOF BT81x.h ********************************************************/

//Change the code below by your sketch
#include "BT81x.h"

TaskHandle_t Gui;
TaskHandle_t Idle;

void GuiTask(void *pvParameters){
uint8_t byte_ret=0;
uint8_t arr[4];
BT815Class GPU; //GPU instantiate in loop() for Arduino
GPU.hwReset();
GPU.cmdWrite(BT815_ACTIVE);
GPU.cmdWrite(BT815_CLKEXT);
GPU.cmdWrite(BT815_CLK60M);
for(;;){
GPU.memReadN(REG_ID, arr, sizeof(arr));
for(int i=0; i<4; i++) {Serial.printf("Array content 0x%x\n",arr[i]);}

vTaskDelay((TickType_t)1000/portTICK_PERIOD_MS);

}
}

void IdleTask(void *pvParameters){
static uint32_t pass=0;

for(;;){
Serial.printf("IdleTask running %ld\n", pass++);
vTaskDelay((TickType_t)1000/portTICK_PERIOD_MS);
}
}

void setup() {
Serial.begin(115200);
xTaskCreatePinnedToCore(
GuiTask,
"GuiTask",
10000,
NULL,
1,
&Gui,
1); //CPU core 1 in use for GuiTask

xTaskCreatePinnedToCore(
IdleTask,
"IdleTask",
10000,
NULL,
1,
&Idle,
0); //CPU core 0 for IdleTask
}

void loop() {

}

Debug Messages:

Enable Core debug level: Debug on tools menu of Arduino IDE, then put the serial output here 
IdleTask running 478
Array content 0x42
Array content 0x0
Array content 0x0
Array content 0x0

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions