From 3af348fb65a26299963cdf1ea846c13b37e4f728 Mon Sep 17 00:00:00 2001 From: Christian Ambach Date: Wed, 31 Oct 2018 09:44:06 +0100 Subject: [PATCH 1/5] Revert "SPI wire interface (experimental)" This reverts commit 00b1faab8358d1575e4567d462a5329201023bc2. --- src/spisend.cpp | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/spisend.cpp b/src/spisend.cpp index 6d28f5a8..c778a887 100644 --- a/src/spisend.cpp +++ b/src/spisend.cpp @@ -41,32 +41,34 @@ void spi_loop(void *pvParameters) { void hal_spi_init() { SPI.begin(SCK, MISO, MOSI, SS); } -void hal_spi_trx(uint8_t port, uint8_t *buf, int len, uint8_t is_read) { +void hal_spi_trx(u1_t cmd, u1_t *buf, int len, u1_t is_read) { + u1_t nss = SS; SPISettings settings(1E6, MSBFIRST, SPI_MODE0); SPI.beginTransaction(settings); - digitalWrite(SS, 0); - SPI.transfer(port); + digitalWrite(nss, 0); - for (uint8_t i = 0; i < len; i++) { - uint8_t *p = buf + i; - uint8_t data = is_read ? 0x00 : *p; + SPI.transfer(cmd); + + for (u1_t i = 0; i < len; i++) { + u1_t *p = buf + i; + u1_t data = is_read ? 0x00 : *p; data = SPI.transfer(data); if (is_read) *p = data; } - digitalWrite(SS, 1); + digitalWrite(nss, 1); SPI.endTransaction(); } -void hal_spi_write(uint8_t port, const uint8_t *buf, int len) { - hal_spi_trx(port, (uint8_t *)buf, len, 0); +void hal_spi_write(u1_t cmd, const u1_t *buf, int len) { + hal_spi_trx(cmd, (u1_t *)buf, len, 0); } -void hal_spi_read(uint8_t port, uint8_t *buf, int len) { - hal_spi_trx(port, buf, len, 1); +void hal_spi_read(u1_t cmd, u1_t *buf, int len) { + hal_spi_trx(cmd, buf, len, 1); } #endif // HAS_SPI \ No newline at end of file From 4cab5113cac68429871197685abea30e8b0609cd Mon Sep 17 00:00:00 2001 From: Christian Ambach Date: Wed, 31 Oct 2018 09:44:16 +0100 Subject: [PATCH 2/5] Revert "SPI code added (experimental)" This reverts commit 16759c4dd55abecc6f51539ba00dffcffc1e29d0. --- include/spisend.h | 25 ------------------------ src/spisend.cpp | 50 +++-------------------------------------------- 2 files changed, 3 insertions(+), 72 deletions(-) diff --git a/include/spisend.h b/include/spisend.h index 70cc4437..750a3c20 100644 --- a/include/spisend.h +++ b/include/spisend.h @@ -1,34 +1,9 @@ #ifndef _SPISEND_H #define _SPISEND_H -#include "globals.h" -#include "spi.h" - extern TaskHandle_t SpiTask; extern QueueHandle_t SPISendQueue; -/* - * Process data in SPI send queue - */ void spi_loop(void *pvParameters); -/* -* initialize local SPI wire interface -*/ -void hal_spi_init(); - -/* - * Perform SPI write transaction on local SPI wire interface - * - write the command byte 'cmd' - * - write 'len' bytes out of 'buf' - */ -void hal_spi_write(uint8_t cmd, const uint8_t* buf, int len); - -/* - * Perform SPI read transaction on local SPI wire interface - * - read the command byte 'cmd' - * - read 'len' bytes into 'buf' - */ -void hal_spi_read(uint8_t cmd, uint8_t* buf, int len); - #endif \ No newline at end of file diff --git a/src/spisend.cpp b/src/spisend.cpp index c778a887..57da9287 100644 --- a/src/spisend.cpp +++ b/src/spisend.cpp @@ -1,6 +1,6 @@ #ifdef HAS_SPI -#include "spisend.h" +#include "globals.h" // Local logging tag static const char TAG[] = "main"; @@ -13,62 +13,18 @@ TaskHandle_t SpiTask; // SPI feed Task void spi_loop(void *pvParameters) { - uint8_t buf[32]; - configASSERT(((uint32_t)pvParameters) == 1); // FreeRTOS check while (1) { - // check if data to send on SPI interface if (xQueueReceive(SPISendQueue, &SendBuffer, (TickType_t)0) == pdTRUE) { - hal_spi_write(SendBuffer.MessagePort, SendBuffer.Message, - SendBuffer.MessageSize); ESP_LOGI(TAG, "%d bytes sent to SPI", SendBuffer.MessageSize); } - - // check if command is received on SPI command port, then call interpreter - hal_spi_read(RCMDPORT, buf, 32); - if (buf[0]) - rcommand(buf, sizeof(buf)); - vTaskDelay(2 / portTICK_PERIOD_MS); // yield to CPU - } // end of infinite loop + + } // end of infinite loop vTaskDelete(NULL); // shoud never be reached } // spi_loop() -// SPI hardware abstraction layer - -void hal_spi_init() { SPI.begin(SCK, MISO, MOSI, SS); } - -void hal_spi_trx(u1_t cmd, u1_t *buf, int len, u1_t is_read) { - - u1_t nss = SS; - SPISettings settings(1E6, MSBFIRST, SPI_MODE0); - SPI.beginTransaction(settings); - - digitalWrite(nss, 0); - - SPI.transfer(cmd); - - for (u1_t i = 0; i < len; i++) { - u1_t *p = buf + i; - u1_t data = is_read ? 0x00 : *p; - data = SPI.transfer(data); - if (is_read) - *p = data; - } - - digitalWrite(nss, 1); - SPI.endTransaction(); -} - -void hal_spi_write(u1_t cmd, const u1_t *buf, int len) { - hal_spi_trx(cmd, (u1_t *)buf, len, 0); -} - -void hal_spi_read(u1_t cmd, u1_t *buf, int len) { - hal_spi_trx(cmd, buf, len, 1); -} - #endif // HAS_SPI \ No newline at end of file From a8043b8d654e5b07a27327332c383c0aa4a87189 Mon Sep 17 00:00:00 2001 From: Christian Ambach Date: Wed, 31 Oct 2018 16:54:45 +0100 Subject: [PATCH 3/5] set log level for LOG_LOCAL_LEVEL otherwise log functions like ESP_LOG_BUFFER_HEXDUMP will not use the defined log level Signed-off-by: Christian Ambach --- platformio.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/platformio.ini b/platformio.ini index a21e5d4a..8d08dbb2 100644 --- a/platformio.ini +++ b/platformio.ini @@ -58,6 +58,7 @@ build_flags = -w '-DARDUINO_LMIC_PROJECT_CONFIG_H=../../../src/lmic_config.h' '-DCORE_DEBUG_LEVEL=${common.debug_level}' + '-DLOG_LOCAL_LEVEL=${common.debug_level}' '-DBINTRAY_PACKAGE="${PIOENV}"' '-DPROGVERSION="${common.release_version}"' From bf3516bf45fe4d57845f2ea2a5818a404d915189 Mon Sep 17 00:00:00 2001 From: Christian Ambach Date: Fri, 2 Nov 2018 09:00:48 +0100 Subject: [PATCH 4/5] fix the build for devices without LoRa Signed-off-by: Christian Ambach --- src/cyclic.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cyclic.cpp b/src/cyclic.cpp index f75daacf..081bb556 100644 --- a/src/cyclic.cpp +++ b/src/cyclic.cpp @@ -3,6 +3,7 @@ // Basic config #include "cyclic.h" +#include "rcommand.h" // Local logging tag static const char TAG[] = "main"; From a3750ef01ba6c633df8400e2ee21dfbc9a30b05c Mon Sep 17 00:00:00 2001 From: Christian Ambach Date: Tue, 11 Sep 2018 16:15:39 +0200 Subject: [PATCH 5/5] 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 --- include/globals.h | 4 -- include/spisend.h | 9 --- include/spislave.h | 36 +++++++++++ src/cyclic.cpp | 7 ++- src/hal/generic.h | 5 ++ src/hal/lopy4.h | 6 ++ src/main.cpp | 20 +----- src/senddata.cpp | 13 ++-- src/spisend.cpp | 30 --------- src/spislave.cpp | 152 +++++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 209 insertions(+), 73 deletions(-) delete mode 100644 include/spisend.h create mode 100644 include/spislave.h delete mode 100644 src/spisend.cpp create mode 100644 src/spislave.cpp diff --git a/include/globals.h b/include/globals.h index 78df4a95..d946b2df 100644 --- a/include/globals.h +++ b/include/globals.h @@ -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 diff --git a/include/spisend.h b/include/spisend.h deleted file mode 100644 index 750a3c20..00000000 --- a/include/spisend.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef _SPISEND_H -#define _SPISEND_H - -extern TaskHandle_t SpiTask; -extern QueueHandle_t SPISendQueue; - -void spi_loop(void *pvParameters); - -#endif \ No newline at end of file diff --git a/include/spislave.h b/include/spislave.h new file mode 100644 index 00000000..526203b9 --- /dev/null +++ b/include/spislave.h @@ -0,0 +1,36 @@ +/* + +//////////////////////// ESP32-Paxcounter \\\\\\\\\\\\\\\\\\\\\\\\\\ + +Copyright 2018 Christian Ambach + + 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 diff --git a/src/cyclic.cpp b/src/cyclic.cpp index 081bb556..d8a0490f 100644 --- a/src/cyclic.cpp +++ b/src/cyclic.cpp @@ -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 diff --git a/src/hal/generic.h b/src/hal/generic.h index 7e2256df..a8a5555d 100644 --- a/src/hal/generic.h +++ b/src/hal/generic.h @@ -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 diff --git a/src/hal/lopy4.h b/src/hal/lopy4.h index 79e80a36..6b93baad 100644 --- a/src/hal/lopy4.h +++ b/src/hal/lopy4.h @@ -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) diff --git a/src/main.cpp b/src/main.cpp index af5fdd4c..de80e718 100644 --- a/src/main.cpp +++ b/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 diff --git a/src/senddata.cpp b/src/senddata.cpp index ee293485..89657114 100644 --- a/src/senddata.cpp +++ b/src/senddata.cpp @@ -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(); } \ No newline at end of file diff --git a/src/spisend.cpp b/src/spisend.cpp deleted file mode 100644 index 57da9287..00000000 --- a/src/spisend.cpp +++ /dev/null @@ -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 \ No newline at end of file diff --git a/src/spislave.cpp b/src/spislave.cpp new file mode 100644 index 00000000..7cd8d729 --- /dev/null +++ b/src/spislave.cpp @@ -0,0 +1,152 @@ +/* + +//////////////////////// ESP32-Paxcounter \\\\\\\\\\\\\\\\\\\\\\\\\\ + +Copyright 2018 Christian Ambach + + 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 +#include +#include + +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 +} \ No newline at end of file