253 lines
5.5 KiB
C++
253 lines
5.5 KiB
C++
#ifndef HARDSPI_H
|
|
#define HARDSPI_H
|
|
|
|
#include "../Debug.h"
|
|
#include "driver/spi_master.h"
|
|
#include <cmath>
|
|
#include <string.h>
|
|
|
|
//static spi_transaction_t trans[2];
|
|
|
|
#define PIN_NUM_MISO GPIO_NUM_19
|
|
#define PIN_NUM_MOSI GPIO_NUM_23
|
|
#define PIN_NUM_CLK GPIO_NUM_18
|
|
#define PIN_NUM_CS GPIO_NUM_2
|
|
|
|
|
|
template <int PIN_NUM_MISO, int PIN_NUM_MOSI, int PIN_NUM_CLK> class HardSPI {
|
|
//class HardSPI {
|
|
|
|
static constexpr int MAX_LEN = 4000;
|
|
|
|
spi_device_handle_t spi;
|
|
|
|
spi_bus_config_t buscfg;
|
|
|
|
spi_device_interface_config_t devcfg;
|
|
|
|
static constexpr const char* TAG = "hwSPI";
|
|
|
|
public:
|
|
|
|
// can be called before every transmit
|
|
// static void IRAM_ATTR pre_transfer_callback(spi_transaction_t *t) {
|
|
// }
|
|
|
|
/** ctor */
|
|
HardSPI() {
|
|
init();
|
|
}
|
|
|
|
private:
|
|
|
|
void init() {
|
|
|
|
int ret;
|
|
|
|
// BUS specific options
|
|
memset(&buscfg, 0, sizeof(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 = MAX_LEN;
|
|
buscfg.flags = 0;
|
|
buscfg.intr_flags = 0;
|
|
|
|
// DEVICE specific options
|
|
memset(&devcfg, 0, sizeof(devcfg));
|
|
devcfg.clock_speed_hz = 10 * 1000 * 1000;
|
|
devcfg.mode = 0;
|
|
devcfg.spics_io_num = -1;//PIN_NUM_CS; // currently not used
|
|
devcfg.queue_size = 2;
|
|
devcfg.pre_cb = nullptr;
|
|
//devcfg.pre_cb = pre_transfer_callback; // can be called before every transmit
|
|
|
|
// Initialize the SPI bus
|
|
ret = spi_bus_initialize(HSPI_HOST, &buscfg, 1);
|
|
ESP_ERROR_CHECK(ret);
|
|
|
|
// Attach the device to the SPI bus
|
|
ret = spi_bus_add_device(HSPI_HOST, &devcfg, &spi);
|
|
ESP_ERROR_CHECK(ret);
|
|
|
|
}
|
|
|
|
public:
|
|
|
|
/** blocking transmit the given bytes */
|
|
void write(const uint8_t* data, size_t len) {
|
|
|
|
spi_transaction_t t;
|
|
|
|
while(len > 0) {
|
|
|
|
// ensure the transaction is reset to defaults.
|
|
// this is mandatory! as the ESP adjusts some parameters while/after sending!
|
|
memset(&t, 0, sizeof(spi_transaction_t));
|
|
|
|
const size_t chunkLen = min(MAX_LEN, (len));
|
|
t.length = 8 * chunkLen; // in bits
|
|
t.tx_buffer = data; // MOSI only
|
|
t.flags = 0;
|
|
|
|
// blocking transfer
|
|
esp_err_t ret = spi_device_polling_transmit(spi, &t);
|
|
ESP_ERROR_CHECK(ret);
|
|
|
|
// update remaining length and data pointer
|
|
len -= chunkLen;
|
|
data += chunkLen;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void read(uint8_t* dst, size_t len) {
|
|
|
|
// sanity check
|
|
{
|
|
const size_t addr = reinterpret_cast<size_t>(dst);
|
|
if ((addr % 4) != 0) {
|
|
ESP_LOGE(TAG, "read-buffer must be 32-bit aligned");
|
|
}
|
|
}
|
|
|
|
spi_transaction_t t;
|
|
memset(&t, 0, sizeof(spi_transaction_t));
|
|
|
|
//debugMod1(TAG, "read %d bytes", len);
|
|
|
|
while(len > 0) {
|
|
|
|
const size_t chunkLen = min(MAX_LEN, (len));
|
|
//ESP_LOGI(TAG, "- read %d byte chunk", chunkLen);
|
|
t.length = 8 * chunkLen; // in bits
|
|
t.rx_buffer = dst; // MISO only
|
|
t.flags = 0;
|
|
|
|
// blocking transfer
|
|
esp_err_t ret = spi_device_polling_transmit(spi, &t);
|
|
ESP_ERROR_CHECK(ret);
|
|
|
|
// update remaining length and destination-data pointer
|
|
len -= chunkLen;
|
|
dst += chunkLen;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/** send 4 bytes onto the bus while reading 4 bytes response */
|
|
uint8_t readWriteByte(uint8_t write) {
|
|
|
|
spi_transaction_t t;
|
|
memset(&t, 0, sizeof(spi_transaction_t));
|
|
t.length = 8*1;
|
|
t.rxlength = 8*1;
|
|
t.tx_data[0] = (write >> 0) & 0xFF;
|
|
t.flags = SPI_TRANS_USE_RXDATA | SPI_TRANS_USE_TXDATA;
|
|
|
|
esp_err_t ret = spi_device_polling_transmit(spi, &t);
|
|
ESP_ERROR_CHECK(ret);
|
|
|
|
return (static_cast<uint32_t>(t.rx_data[0]));
|
|
|
|
}
|
|
|
|
/** send 4 bytes onto the bus while reading 4 bytes response */
|
|
uint32_t readWriteQuad(uint32_t write) {
|
|
|
|
spi_transaction_t t;
|
|
memset(&t, 0, sizeof(spi_transaction_t));
|
|
t.length = 8*4;
|
|
t.rxlength = 8*4;
|
|
t.tx_data[0] = (write >> 24) & 0xFF;
|
|
t.tx_data[1] = (write >> 16) & 0xFF;
|
|
t.tx_data[2] = (write >> 8) & 0xFF;
|
|
t.tx_data[3] = (write >> 0) & 0xFF;
|
|
t.flags = SPI_TRANS_USE_RXDATA | SPI_TRANS_USE_TXDATA;
|
|
|
|
esp_err_t ret = spi_device_polling_transmit(spi, &t);
|
|
ESP_ERROR_CHECK(ret);
|
|
|
|
return
|
|
(static_cast<uint32_t>(t.rx_data[0]) << 24) |
|
|
(static_cast<uint32_t>(t.rx_data[1]) << 16) |
|
|
(static_cast<uint32_t>(t.rx_data[2]) << 8) |
|
|
(static_cast<uint32_t>(t.rx_data[3]) << 0);
|
|
|
|
}
|
|
|
|
|
|
/** read one byte from the bus */
|
|
uint8_t readByte() {
|
|
|
|
spi_transaction_t t;
|
|
memset(&t, 0, sizeof(spi_transaction_t));
|
|
t.length = 8*1;
|
|
t.flags = SPI_TRANS_USE_RXDATA;
|
|
|
|
esp_err_t ret = spi_device_polling_transmit(spi, &t);
|
|
ESP_ERROR_CHECK(ret);
|
|
|
|
return t.rx_data[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
void writeByte(const uint8_t byte) {
|
|
|
|
spi_transaction_t t;
|
|
memset(&t, 0, sizeof(spi_transaction_t));
|
|
t.length = 8*1;
|
|
t.tx_data[0] = byte;
|
|
t.flags = SPI_TRANS_USE_TXDATA;
|
|
|
|
esp_err_t ret = spi_device_polling_transmit(spi, &t);
|
|
ESP_ERROR_CHECK(ret);
|
|
|
|
}
|
|
|
|
void writeWord(const uint16_t word) {
|
|
|
|
spi_transaction_t t;
|
|
memset(&t, 0, sizeof(spi_transaction_t));
|
|
t.length = 8*2;
|
|
t.tx_data[0] = static_cast<uint8_t>(word>>8);
|
|
t.tx_data[1] = static_cast<uint8_t>(word>>0);
|
|
t.flags = SPI_TRANS_USE_TXDATA;
|
|
|
|
esp_err_t ret = spi_device_polling_transmit(spi, &t);
|
|
ESP_ERROR_CHECK(ret);
|
|
|
|
}
|
|
|
|
void writeQuad(const uint32_t quad) {
|
|
|
|
spi_transaction_t t;
|
|
memset(&t, 0, sizeof(spi_transaction_t));
|
|
t.length = 8*4;
|
|
t.tx_data[0] = static_cast<uint8_t>(quad>>24);
|
|
t.tx_data[1] = static_cast<uint8_t>(quad>>16);
|
|
t.tx_data[2] = static_cast<uint8_t>(quad>>8);
|
|
t.tx_data[3] = static_cast<uint8_t>(quad>>0);
|
|
t.flags = SPI_TRANS_USE_TXDATA;
|
|
|
|
esp_err_t ret = spi_device_polling_transmit(spi, &t);
|
|
ESP_ERROR_CHECK(ret);
|
|
|
|
}
|
|
|
|
static size_t min(size_t a, size_t b) {
|
|
return (a < b) ? a : b;
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
#endif // HARDSPI_H
|