add SPI slave support
Set up SPI slave transactions for entries in the SPI send queue. Add a header to each SPI datagram that includes a CRC16, the type and the size of the message that follows. Does not act on received bytes (yet). Signed-off-by: Christian Ambach <christian.ambach@deutschebahn.com>
This commit is contained in:
parent
bf3516bf45
commit
a3750ef01b
@ -66,10 +66,6 @@ extern TaskHandle_t irqHandlerTask, wifiSwitchTask;
|
||||
#include "lorawan.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAS_SPI
|
||||
#include "spisend.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAS_DISPLAY
|
||||
#include "display.h"
|
||||
#endif
|
||||
|
@ -1,9 +0,0 @@
|
||||
#ifndef _SPISEND_H
|
||||
#define _SPISEND_H
|
||||
|
||||
extern TaskHandle_t SpiTask;
|
||||
extern QueueHandle_t SPISendQueue;
|
||||
|
||||
void spi_loop(void *pvParameters);
|
||||
|
||||
#endif
|
36
include/spislave.h
Normal file
36
include/spislave.h
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
|
||||
//////////////////////// ESP32-Paxcounter \\\\\\\\\\\\\\\\\\\\\\\\\\
|
||||
|
||||
Copyright 2018 Christian Ambach <christian.ambach@deutschebahn.com>
|
||||
|
||||
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.
|
||||
|
||||
NOTICE:
|
||||
Parts of the source files in this repository are made available under different
|
||||
licenses. Refer to LICENSE.txt file in repository for more details.
|
||||
|
||||
*/
|
||||
#ifndef _SPISLAVE_H
|
||||
#define _SPISLAVE_H
|
||||
|
||||
#include "globals.h"
|
||||
|
||||
esp_err_t spi_init();
|
||||
|
||||
void spi_enqueuedata(uint8_t messageType, MessageBuffer_t *message);
|
||||
void spi_queuereset();
|
||||
|
||||
void spi_housekeeping();
|
||||
|
||||
#endif // _SPISLAVE_H
|
@ -4,6 +4,7 @@
|
||||
// Basic config
|
||||
#include "cyclic.h"
|
||||
#include "rcommand.h"
|
||||
#include "spislave.h"
|
||||
|
||||
// Local logging tag
|
||||
static const char TAG[] = "main";
|
||||
@ -26,9 +27,9 @@ void doHousekeeping() {
|
||||
#ifdef HAS_GPS
|
||||
ESP_LOGD(TAG, "Gpsloop %d bytes left", uxTaskGetStackHighWaterMark(GpsTask));
|
||||
#endif
|
||||
#ifdef HAS_SPI
|
||||
ESP_LOGD(TAG, "Spiloop %d bytes left", uxTaskGetStackHighWaterMark(SpiTask));
|
||||
#endif
|
||||
|
||||
spi_housekeeping();
|
||||
|
||||
#if (HAS_LED != NOT_A_PIN) || defined(HAS_RGB_LED)
|
||||
ESP_LOGD(TAG, "LEDloop %d bytes left", uxTaskGetStackHighWaterMark(ledLoopTask));
|
||||
#endif
|
||||
|
@ -7,6 +7,11 @@
|
||||
|
||||
#define HAS_LORA 1 // comment out if device shall not send data via LoRa or has no LoRa
|
||||
#define HAS_SPI 1 // comment out if device shall not send data via SPI
|
||||
// pin definitions for SPI slave interface
|
||||
#define SPI_MOSI GPIO_NUM_23
|
||||
#define SPI_MISO GPIO_NUM_19
|
||||
#define SPI_SCLK GPIO_NUM_18
|
||||
#define SPI_CS GPIO_NUM_5
|
||||
|
||||
#define CFG_sx1276_radio 1 // select LoRa chip
|
||||
//#define CFG_sx1272_radio 1 // select LoRa chip
|
||||
|
@ -7,6 +7,12 @@
|
||||
|
||||
#define HAS_LORA 1 // comment out if device shall not send data via LoRa
|
||||
#define HAS_SPI 1 // comment out if device shall not send data via SPI
|
||||
// pin definitions for SPI slave interface
|
||||
#define SPI_MOSI GPIO_NUM_22
|
||||
#define SPI_MISO GPIO_NUM_33
|
||||
#define SPI_SCLK GPIO_NUM_26
|
||||
#define SPI_CS GPIO_NUM_36
|
||||
|
||||
#define CFG_sx1276_radio 1
|
||||
//#define HAS_LED NOT_A_PIN // LoPy4 has no on board mono LED, we use on board RGB LED
|
||||
#define HAS_RGB_LED (0) // WS2812B RGB LED on GPIO0 (P2)
|
||||
|
20
src/main.cpp
20
src/main.cpp
@ -48,6 +48,7 @@ ESP32 hardware timers
|
||||
|
||||
// Basic Config
|
||||
#include "main.h"
|
||||
#include "spislave.h"
|
||||
|
||||
configData_t cfg; // struct holds current device configuration
|
||||
char display_line6[16], display_line7[16]; // display buffers
|
||||
@ -197,14 +198,8 @@ void setup() {
|
||||
// initialize SPI
|
||||
#ifdef HAS_SPI
|
||||
strcat_P(features, " SPI");
|
||||
SPISendQueue = xQueueCreate(SEND_QUEUE_SIZE, sizeof(MessageBuffer_t));
|
||||
if (SPISendQueue == 0) {
|
||||
ESP_LOGE(TAG, "Could not create SPI send queue. Aborting.");
|
||||
exit(0);
|
||||
} else
|
||||
ESP_LOGI(TAG, "SPI send queue created, size %d Bytes",
|
||||
SEND_QUEUE_SIZE * PAYLOAD_BUFFER_SIZE);
|
||||
#endif
|
||||
assert(spi_init() == ESP_OK);
|
||||
|
||||
#ifdef VENDORFILTER
|
||||
strcat_P(features, " OUIFLT");
|
||||
@ -312,17 +307,6 @@ void setup() {
|
||||
1); // CPU core
|
||||
#endif
|
||||
|
||||
#ifdef HAS_SPI
|
||||
ESP_LOGI(TAG, "Starting SPIloop...");
|
||||
xTaskCreatePinnedToCore(spi_loop, // task function
|
||||
"spiloop", // name of task
|
||||
2048, // stack size of task
|
||||
(void *)1, // parameter of the task
|
||||
2, // priority of the task
|
||||
&SpiTask, // task handle
|
||||
0); // CPU core
|
||||
#endif
|
||||
|
||||
// start state machine
|
||||
ESP_LOGI(TAG, "Starting IRQ Handler...");
|
||||
xTaskCreatePinnedToCore(irqHandler, // task function
|
||||
|
@ -1,5 +1,6 @@
|
||||
// Basic Config
|
||||
#include "globals.h"
|
||||
#include "spislave.h"
|
||||
|
||||
// put data to send in RTos Queues used for transmit over channels Lora and SPI
|
||||
void SendData(uint8_t port) {
|
||||
@ -19,12 +20,7 @@ void SendData(uint8_t port) {
|
||||
ESP_LOGI(TAG, "%d bytes enqueued to send on LoRa", payload.getSize());
|
||||
#endif
|
||||
|
||||
// enqueue message in SPI send queue
|
||||
#ifdef HAS_SPI
|
||||
if (xQueueSendToBack(SPISendQueue, (void *)&SendBuffer, (TickType_t)0) ==
|
||||
pdTRUE)
|
||||
ESP_LOGI(TAG, "%d bytes enqueued to send on SPI", payload.getSize());
|
||||
#endif
|
||||
spi_enqueuedata(port, &SendBuffer);
|
||||
|
||||
// clear counter if not in cumulative counter mode
|
||||
if ((port == COUNTERPORT) && (cfg.countermode != 1)) {
|
||||
@ -66,7 +62,6 @@ void flushQueues() {
|
||||
#ifdef HAS_LORA
|
||||
xQueueReset(LoraSendQueue);
|
||||
#endif
|
||||
#ifdef HAS_SPI
|
||||
xQueueReset(SPISendQueue);
|
||||
#endif
|
||||
|
||||
spi_queuereset();
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
#ifdef HAS_SPI
|
||||
|
||||
#include "globals.h"
|
||||
|
||||
// Local logging tag
|
||||
static const char TAG[] = "main";
|
||||
|
||||
MessageBuffer_t SendBuffer;
|
||||
|
||||
QueueHandle_t SPISendQueue;
|
||||
TaskHandle_t SpiTask;
|
||||
|
||||
// SPI feed Task
|
||||
void spi_loop(void *pvParameters) {
|
||||
|
||||
configASSERT(((uint32_t)pvParameters) == 1); // FreeRTOS check
|
||||
|
||||
while (1) {
|
||||
if (xQueueReceive(SPISendQueue, &SendBuffer, (TickType_t)0) == pdTRUE) {
|
||||
ESP_LOGI(TAG, "%d bytes sent to SPI", SendBuffer.MessageSize);
|
||||
}
|
||||
vTaskDelay(2 / portTICK_PERIOD_MS); // yield to CPU
|
||||
|
||||
} // end of infinite loop
|
||||
|
||||
vTaskDelete(NULL); // shoud never be reached
|
||||
|
||||
} // spi_loop()
|
||||
|
||||
#endif // HAS_SPI
|
152
src/spislave.cpp
Normal file
152
src/spislave.cpp
Normal file
@ -0,0 +1,152 @@
|
||||
/*
|
||||
|
||||
//////////////////////// ESP32-Paxcounter \\\\\\\\\\\\\\\\\\\\\\\\\\
|
||||
|
||||
Copyright 2018 Christian Ambach <christian.ambach@deutschebahn.com>
|
||||
|
||||
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.
|
||||
|
||||
NOTICE:
|
||||
Parts of the source files in this repository are made available under different
|
||||
licenses. Refer to LICENSE.txt file in repository for more details.
|
||||
|
||||
*/
|
||||
|
||||
#include "spislave.h"
|
||||
|
||||
#include <driver/spi_slave.h>
|
||||
#include <sys/param.h>
|
||||
#include <rom/crc.h>
|
||||
|
||||
static const char TAG[] = __FILE__;
|
||||
|
||||
#define HEADER_SIZE 4
|
||||
// SPI transaction size needs to be at least 8 bytes and dividable by 4, see
|
||||
// https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/spi_slave.html
|
||||
#define BUFFER_SIZE \
|
||||
(MAX(8, HEADER_SIZE + PAYLOAD_BUFFER_SIZE) + \
|
||||
(4 - MAX(8, HEADER_SIZE + PAYLOAD_BUFFER_SIZE) % 4))
|
||||
DMA_ATTR uint8_t txbuf[BUFFER_SIZE];
|
||||
DMA_ATTR uint8_t rxbuf[BUFFER_SIZE];
|
||||
|
||||
QueueHandle_t SPISendQueue;
|
||||
|
||||
TaskHandle_t spiTask;
|
||||
|
||||
void spi_slave_task(void *param) {
|
||||
while (1) {
|
||||
MessageBuffer_t msg;
|
||||
size_t transaction_size;
|
||||
|
||||
memset(txbuf, 0, sizeof(txbuf));
|
||||
memset(rxbuf, 0, sizeof(rxbuf));
|
||||
|
||||
if (xQueueReceive(SPISendQueue, &msg, portMAX_DELAY) != pdTRUE) {
|
||||
ESP_LOGE(TAG, "Premature return from xQueueReceive() with no data!");
|
||||
continue;
|
||||
}
|
||||
|
||||
uint8_t *messageType = txbuf + 2;
|
||||
*messageType = msg.MessagePort;
|
||||
uint8_t *messageSize = txbuf + 3;
|
||||
*messageSize = msg.MessageSize;
|
||||
memcpy(txbuf + HEADER_SIZE, &msg.Message, msg.MessageSize);
|
||||
|
||||
transaction_size = HEADER_SIZE + msg.MessageSize;
|
||||
transaction_size += (4 - transaction_size % 4);
|
||||
|
||||
uint16_t *crc = (uint16_t *)txbuf;
|
||||
*crc = crc16_be(0, messageType, msg.MessageSize + HEADER_SIZE - 2);
|
||||
|
||||
spi_slave_transaction_t spi_transaction = {0};
|
||||
spi_transaction.length = transaction_size * 8;
|
||||
spi_transaction.tx_buffer = txbuf;
|
||||
spi_transaction.rx_buffer = rxbuf;
|
||||
|
||||
ESP_LOGI(TAG, "Prepared SPI transaction for %zu bytes", transaction_size);
|
||||
ESP_LOG_BUFFER_HEXDUMP(TAG, txbuf, transaction_size, ESP_LOG_DEBUG);
|
||||
esp_err_t ret =
|
||||
spi_slave_transmit(HSPI_HOST, &spi_transaction, portMAX_DELAY);
|
||||
ESP_LOG_BUFFER_HEXDUMP(TAG, rxbuf, transaction_size, ESP_LOG_DEBUG);
|
||||
ESP_LOGI(TAG, "Transaction finished with size %zu bits",
|
||||
spi_transaction.trans_len);
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t spi_init() {
|
||||
#ifndef HAS_SPI
|
||||
return ESP_OK;
|
||||
#else
|
||||
|
||||
SPISendQueue = xQueueCreate(SEND_QUEUE_SIZE, sizeof(MessageBuffer_t));
|
||||
if (SPISendQueue == 0) {
|
||||
ESP_LOGE(TAG, "Could not create SPI send queue. Aborting.");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
ESP_LOGI(TAG, "SPI send queue created, size %d Bytes",
|
||||
SEND_QUEUE_SIZE * PAYLOAD_BUFFER_SIZE);
|
||||
|
||||
spi_bus_config_t spi_bus_cfg = {.mosi_io_num = SPI_MOSI,
|
||||
.miso_io_num = SPI_MISO,
|
||||
.sclk_io_num = SPI_SCLK,
|
||||
.quadwp_io_num = -1,
|
||||
.quadhd_io_num = -1,
|
||||
.max_transfer_sz = 0,
|
||||
.flags = 0};
|
||||
|
||||
spi_slave_interface_config_t spi_slv_cfg = {.spics_io_num = SPI_CS,
|
||||
.flags = 0,
|
||||
.queue_size = 1,
|
||||
.mode = 0,
|
||||
.post_setup_cb = NULL,
|
||||
.post_trans_cb = NULL};
|
||||
|
||||
gpio_set_pull_mode(SPI_MOSI, GPIO_PULLUP_ONLY);
|
||||
gpio_set_pull_mode(SPI_SCLK, GPIO_PULLUP_ONLY);
|
||||
gpio_set_pull_mode(SPI_CS, GPIO_PULLUP_ONLY);
|
||||
|
||||
ESP_LOGI(TAG, "Starting SPIloop...");
|
||||
xTaskCreate(spi_slave_task, "spiloop", 4096, (void *)NULL, 2, &spiTask);
|
||||
|
||||
esp_err_t ret =
|
||||
spi_slave_initialize(HSPI_HOST, &spi_bus_cfg, &spi_slv_cfg, 1);
|
||||
return ret;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
void spi_enqueuedata(uint8_t messageType, MessageBuffer_t *message) {
|
||||
// enqueue message in SPI send queue
|
||||
#ifdef HAS_SPI
|
||||
BaseType_t ret =
|
||||
xQueueSendToBack(SPISendQueue, (void *)message, (TickType_t)0);
|
||||
if (ret == pdTRUE) {
|
||||
ESP_LOGI(TAG, "%d bytes enqueued for SPI consumption",
|
||||
message->MessageSize);
|
||||
} else {
|
||||
ESP_LOGW(TAG, "SPI sendqueue is full");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void spi_queuereset(void) {
|
||||
#ifdef HAS_SPI
|
||||
xQueueReset(SPISendQueue);
|
||||
#endif
|
||||
}
|
||||
|
||||
void spi_housekeeping(void) {
|
||||
#ifdef HAS_SPI
|
||||
ESP_LOGD(TAG, "spiloop %d bytes left", uxTaskGetStackHighWaterMark(spiTask));
|
||||
#endif
|
||||
}
|
Loading…
Reference in New Issue
Block a user