#include "spi_slave_server.h"
#include "shared_data.h"
#include <string.h>
// spi
#include <SPI.h>
#include <ESP32SPISlave.h>
#include "helper.h"
ESP32SPISlave slave; // 创建ESP32SPISlave对象
static bool battery_data_sent = false; // 防止重复填充缓存
#define SPI_SPLAVE_ENABLE 1
// Adafruit_SPIDevice spi_dev = Adafruit_SPIDevice(SPIDEVICE_CS, 1000000, SPI_BITORDER_MSBFIRST, SPI_MODE0);
#define MY_CS 12
#define MY_SCK 13
#define MY_MOSI 14
#define MY_MISO 11 // 自定义spi引脚
// SPIClass my_spi(HSPI); // 创建SPIClass对象my_spi
#define SPI_READ_TIMEROUT 999999 // 10 // 50ms
static constexpr size_t SPI_BUFFER_SIZE = 128; // 上位机 测试42 字节数据正常,模式1,定义SPI通信缓冲区大小为32字节
static constexpr size_t QUEUE_SIZE = 1;
static uint8_t spi_tx_buf[SPI_BUFFER_SIZE]{1, 2, 3, 4, 5, 6, 7, 8};//发送缓冲区,预置测试数据1-8
static uint8_t spi_rx_buf[SPI_BUFFER_SIZE]{0, 0, 0, 0, 0, 0, 0, 0};//接收缓冲区,初始化为全0
static uint8_t spi_tx_cmd_buf[SPI_BUFFER_SIZE]{0, 0, 0, 0, 0, 0, 0, 0};//命令发送缓冲区,初始化为全0
#define SPI_TX_CACHE_BUF_LEN 1024//发送缓存总大小为1024字节
#define SPI_TX_PAGE_BUF_LEN (SPI_BUFFER_SIZE - 3) // spi 回复数据的最大长度,单次SPI通信有效数据长度
#define SPI_USER_CMD_NULL 0//空指令
#define SPI_USER_CMD_READ 1//读数据
#define SPI_USER_CMD_WRITE 2//写数据
static volatile uint8_t spi_tx_cache_buf[SPI_TX_CACHE_BUF_LEN]{0, 0, 0, 0, 0, 0, 0, 0};
static volatile int spi_tx_cache_buf_cnt = 0; // spi 发送缓存区数据长度
// static int spi_tx_page_cnt=0;//spi 发送缓存区数据长度
static volatile int spi_current_cmd = 0, spi_current_cmd_len = 0;
static uint8_t spi_send_busy = 0;//发送忙标志位
static uint8_t spi_send_mode = 1; // 发送模式选择发串口
int spi_slave_data_cache_add(uint8_t *data, uint16_t len)
{
if (len > SPI_TX_CACHE_BUF_LEN)
{
/* code */
len = SPI_TX_CACHE_BUF_LEN;
}
for (int i = 0; i < len; i++)
{
/* code */
spi_tx_cache_buf[i] = data[i];
}
spi_tx_cache_buf_cnt = len;
return 0;
}
void IRAM_ATTR my_post_setup_cb(spi_slave_transaction_t *trans)
{
// ==== Step 1: 尝试从 BLE 获取最新数据并写入 spi_tx_cache_buf ====
if (json_updated && !battery_data_sent) {
portENTER_CRITICAL_ISR(&json_mutex);
int len = strlen(latest_battery_json);
if (len > 0 && len < SPI_TX_CACHE_BUF_LEN) {
memset((void*)spi_tx_cache_buf, 0, SPI_TX_CACHE_BUF_LEN);
memcpy((void*)spi_tx_cache_buf, latest_battery_json, len);
spi_tx_cache_buf_cnt = len;
battery_data_sent = true; // 标记已加载
}
json_updated = false; // 清除标志
portEXIT_CRITICAL_ISR(&json_mutex);
}
// ==== Step 2: 计算本次应发送的数据段 ====
int over_len = spi_tx_cache_buf_cnt - spi_current_cmd_len * SPI_TX_PAGE_BUF_LEN;
if (over_len <= 0) {
// 数据已发完,重置状态以便下次更新
if (over_len < 0) return;
// 最后一包发完后复位,等待新数据
if (spi_current_cmd_len > 0) {
battery_data_sent = false; // 允许下一次更新
spi_current_cmd_len = 0;
}
return;
}
if (over_len > SPI_TX_PAGE_BUF_LEN) {
over_len = SPI_TX_PAGE_BUF_LEN;
}
// ==== Step 3: 填充 TX 缓冲区 ====
// 在 my_post_setup_cb 中:
memset((void *)spi_tx_buf, 0, SPI_BUFFER_SIZE);
spi_tx_buf[0] = 0xab;
spi_tx_buf[1] = over_len;
spi_tx_buf[2] = spi_current_cmd_len;
// 如果是第0包,插入总长度(高位在前)
if (spi_current_cmd_len == 0) {
spi_tx_buf[3] = (spi_tx_cache_buf_cnt >> 8) & 0xFF; // high
spi_tx_buf[4] = spi_tx_cache_buf_cnt & 0xFF; // low
// 数据从第5字节开始
int payload_size = (over_len < (SPI_BUFFER_SIZE - 5)) ? over_len : (SPI_BUFFER_SIZE - 5);
for (int i = 0; i < payload_size; i++) {
spi_tx_buf[5 + i] = spi_tx_cache_buf[i];
}
spi_tx_buf[1] = payload_size + 2; // 实际发送长度 = 数据 + 两个长度字节
} else {
// 普通包:直接发送数据
for (int i = 0; i < over_len; i++) {
spi_tx_buf[3 + i] = spi_tx_cache_buf[(spi_current_cmd_len - 1) * SPI_TX_PAGE_BUF_LEN + i];
}
}
spi_current_cmd_len++;
}
/***
* spi slave 任务
* 模式设置4 字节
* spi cmd: 0xaa 0x01 ,切换模式1,发串口1数据
*
* 数据读取 64字节,发aa 01 0xff ......
* spi ack: 0xaa 0x01 ,剩余字节全部回复串口数据
*/
static void spi_slave_task(void *pvParameters)
{
size_t received_bytes;
while (1) {
int cs = digitalRead(MY_CS);
#if SPI_SPLAVE_ENABLE
if (cs == 0) {
memset(spi_rx_buf, 0, SPI_BUFFER_SIZE);
received_bytes = slave.transfer(spi_tx_buf, spi_rx_buf, SPI_BUFFER_SIZE, SPI_READ_TIMEROUT);
if (received_bytes > 0) {
#if 0
printf_log_hex("slave", spi_rx_buf, received_bytes);
#endif
// 检查是否是请求命令(如 AA 01)
if (spi_rx_buf[0] == 0xAA) {
uint8_t cmd = spi_rx_buf[1];
// 示例:收到 AA 01 表示请求数据
if (cmd == 0x01) {
// 不做任何事 —— 下一次 transfer 会由 my_post_setup_cb 自动填充数据
Serial.println("SPI: 收到 AA 01 请求,准备回传电池数据");
}
}
}
}
#endif
vTaskDelay(5 / portTICK_PERIOD_MS);
}
}
/**
* spi slave 初始化
* SPI_MODE1
* sck 13
* miso 14
* mosi 11
* ss 12
*
*/
void spi_slave_server_init(void)
{
#if SPI_SPLAVE_ENABLE
slave.setDataMode(SPI_MODE3);
slave.setQueueSize(QUEUE_SIZE);
slave.begin(HSPI, MY_SCK, MY_MISO, MY_MOSI, MY_CS); // 推荐显式命名引脚
// 注册 post-setup 回调(关键!)
slave.setPostSetupCb(my_post_setup_cb);
xTaskCreate(spi_slave_task, "spi_slave_task", 8 * 1024, NULL, 2, NULL);
Serial.println("SPI Slave 已启动,等待主机访问...");
#endif
}
ESP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0x1 (POWERON),boot:0x28 (SPI_FAST_FLASH_BOOT)
SPIWP:0xee
mode:DIO, clock div:1
load:0x3fce3808,len:0x4bc
load:0x403c9700,len:0xbd8
load:0x403cc700,len:0x2a0c
entry 0x403c98d0
E (202) esp_core_dump_flash: Core dump data check failed:
Calculated checksum='84797ec0'
Image checksum='ffffffff'
uart1_init... baud_rate=115200,rx= 5,tx= 4
SPI Slave 已启动,等待主机访问...
初始化 BLE 主机...
Guru Meditation Error: Core 1 panic'ed (Double exception).
Core 1 register dump:
PC : 0x4037f18e PS : 0x00040136 A0 : 0x8037f9eb A1 : 0x3fced480
A2 : 0x00040136 A3 : 0x00040026 A4 : 0x3fcf0858 A5 : 0x0000004c
A6 : 0x3fcf04a0 A7 : 0x00000001 A8 : 0x3fced540 A9 : 0x00000000
A10 : 0x00000054 A11 : 0xffffffff A12 : 0x00000000 A13 : 0x00001800
A14 : 0x00060523 A15 : 0x00000001 SAR : 0x00000004 EXCCAUSE: 0x00000002
EXCVADDR: 0x00000000 LBEG : 0x400556d5 LEND : 0x400556e5 LCOUNT : 0xfffffff9
Backtrace: 0x4037f18b:0x3fced480 0x4037f9e8:0x00060f23 |<-CORRUPTED
ELF file SHA256: 9c14ee0b4f8a43af
Rebooting...