This commit is contained in:
Roy_01
2026-04-01 13:20:13 +08:00
parent 16d792d62b
commit a4ebbbbabc
9 changed files with 1263 additions and 4 deletions
@@ -21,4 +21,6 @@ void pwm_disable();
void pwm_brake();
void uart_config();
void UART_Send_Wait(UART_Type *pHUart, uint16_t value);
void spi_config(void);
void spi_send_daq_packet(DAQ_Packet_t *pkt);
#endif /* INC_INIT_H_ */
@@ -37,6 +37,7 @@ extern "C"
extern volatile bool flag_24Khz_timer;
extern volatile bool stringComplete;
extern volatile char rxBuffer[128];
extern long ADC_DATA[10]; // ADC 量測資料 (isr.c 填充)
//=============================================================================
// Private Function Definition
//=============================================================================
@@ -47,6 +48,7 @@ extern "C"
void isr_epwm_handle(void);
void isr_adc_handle(void);
void isr_uart0_handle(void);
void SPIx_Handler(void);
#ifdef __cplusplus
}
#endif
@@ -20,6 +20,8 @@ extern "C"
#include "hal_device.h"
#include "syslog.h"
#include "hal_spi.h"
#include "hal_crc.h"
//=============================================================================
// Constant Definition
//=============================================================================
@@ -54,6 +56,31 @@ extern "C"
extern struct dds_param_t dds;
//=========================================================================
// DAQ Packet: 24kHz SPI 資料封包
// 注意: pack(1) 確保結構無 padding,大小固定 = 34 bytes
//=========================================================================
#pragma pack(push, 1)
typedef struct {
uint16_t header; // 0x55AA 封包頭
uint32_t timestamp; // 系統微秒時間戳
int16_t i_u; // U相電流
int16_t i_v; // V相電流
int16_t i_w; // W相電流
uint16_t v_u; // U相電壓
uint16_t v_v; // V相電壓
uint16_t v_w; // W相電壓
uint16_t v_bus; // 母線電壓
int32_t dds_ftw; // 頻率常數
uint32_t dds_amp; // 電壓倍率常數
int16_t error_val; // 狀態碼/誤差值
uint16_t crc16; // 硬體 CRC 校驗碼
} DAQ_Packet_t;
#pragma pack(pop)
// send_daq_enabled: test_data:1 啟動, test_data:0 停止
extern volatile bool send_daq_enabled;
#ifdef __cplusplus
}
#endif
@@ -35,13 +35,14 @@ void SYS_Config()
sys_delay(3000);
/* Disable ICE I/O */
SYSCFG_SetICEPin2NormalIO(true);
//SYSCFG_SetICEPin2NormalIO(true);
gpio_config();
opa_config();
adc_config();
pwm_config();
uart_config();
spi_config(); /* SPI Master 初始化,必須在 gpio_config 之後呼叫 */
__enable_irq();
}
@@ -81,7 +82,23 @@ void gpio_config()
GPIO_InitADC.GPIO_Pin = GPIO_Pin_06 | GPIO_Pin_12;
GPIO_InitADC.GPIO_Mode = GPIO_Mode_ANAL;
GPIO_Init(GPIOA, &GPIO_InitADC);
#if 1
//-----------------//
// SPI
// PB0:MISO PA15:MOSI PA14:CLK
//-----------------//
GPIO_InitTypeDef GPIO_InitSPI;
GPIO_InitSPI.GPIO_Pin = GPIO_Pin_14 | GPIO_Pin_15;
GPIO_InitSPI.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitSPI.GPIO_AF_Mode = GPIO_AF_3;
GPIO_Init(GPIOA, &GPIO_InitSPI);
GPIO_InitSPI.GPIO_Pin = GPIO_Pin_00;
GPIO_InitSPI.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitSPI.GPIO_AF_Mode = GPIO_AF_3;
GPIO_Init(GPIOB, &GPIO_InitSPI);
#if 0
//-----------------//
// test
//-----------------//
@@ -263,3 +280,57 @@ void UART_Send_Wait(UART_Type *pHUart, uint16_t value)
UART_SendData(pHUart, value);
UART_WaitTxFifoEmpty(pHUart);
}
void spi_config(void)
{
SPI_InitTypeDef SPI_InitStruct = { 0 };
SPI_DeInit(SPI0);
SPI_InitStruct.SPI_Mode = SPI_Mode_Master;
SPI_InitStruct.SPI_CPOL = SPI_CPOL_Low; /* 閒置時鐘脅為 Low */
SPI_InitStruct.SPI_CPHA = SPI_CPHA_Effective; /* 第二個時脈檡取樣 */
SPI_InitStruct.SPI_TxDataSize = SPI_TxDataSize_8b; /* 8-bit 传輸 */
SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudratePrescaler_4; /* 60MHz/4 = 15MHz SCK */
SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_Init(SPI0, &SPI_InitStruct);
/* --- 啟動 CRC16 硬體模組 --- */
CRC_Init();
/* Enable SPI */
SPI_Enable(SPI0);
sys_irq_attr_t irq_attr = { .trig_mode = SYS_IRQ_TRIGGER_LEVEL, };
sys_register_IRQ(SPI0_IRQn, SPIx_Handler, &irq_attr);
sys_enable_girq();
}
/* ===========================================================================
* spi_send_daq_packet()
*
* 將 DAQ_Packet_t 封包經 SPI0 逐位元組位元傳輸出去
*
* 每個 byte 備給 SPI TX FIFO,用 polling 方式等待 TXNFUL
* 封包大小 = sizeof(DAQ_Packet_t) = 34 bytes
* ===========================================================================
*/
void spi_send_daq_packet(DAQ_Packet_t *pkt)
{
/* 計算 CRC16:涵蓋 header 到 error_val,不含 crc16 欄位 itself */
uint8_t *raw = (uint8_t *)pkt;
uint32_t payload_len = sizeof(DAQ_Packet_t) - sizeof(uint16_t); /* 排除最後 2 bytes crc */
pkt->crc16 = (uint16_t)CRC_CalcBlockCRC(raw, (int)payload_len, CRC_Width_CRC16);
/* 逐 byte polling 發送 */
uint32_t len = sizeof(DAQ_Packet_t);
for (uint32_t i = 0; i < len; i++)
{
/* 等 TX FIFO 非滿 */
while (SPI_GetFlagStatus(SPI0, SPI_TXFUL_Flag) != 0);
SPI_SendData(SPI0, raw[i]);
}
/* 等待傳輸完成 */
while (SPI_GetFlagStatus(SPI0, SPI_BUSY_Flag) != 0);
}
@@ -75,3 +75,14 @@ __INTERRUPT void isr_uart0_handle(void)
}
}
}
/* SPI IRQ Handler
* DAQ \u5c01\u5305\u7d93 spi_send_daq_packet() \u4ee5 polling \u65b9\u5f0f\u767c\u9001\uff0c\u4e0d\u9700\u8981\u4e2d\u65b7\u9a45\u52d5\u3002
* SPIx_Handler \u4fdd\u7559\u7a7a\u6a21\uff0c\u4ee5\u5c0d\u61c9 spi_config() \u4e2d\u7684 sys_register_IRQ \u3002 */
__INTERRUPT void SPIx_Handler(void)
{
SAVE_IRQ_CSR_CONTEXT();
/* \u76ee\u524d\u7a7a\u767d\uff1aDAQ SPI \u4f7f\u7528 polling \u6a21\u5f0f\uff0c\u4e0d\u9700\u9032\u884c\u4e2d\u65b7\u64cd\u4f5c */
RESTORE_IRQ_CSR_CONTEXT();
return;
}
@@ -87,6 +87,9 @@ struct dds_param_t dds = { 0 };
const uint32_t phase_offset[PHASE_COUNT] = { 0, 1398101, 2796203 };
static struct dds_cal_param phase[PHASE_COUNT] = { 0 };
// DAQ 傳輸啟用旗標: test_data:1 啟動, test_data:0 停止
volatile bool send_daq_enabled = false;
void dds_pwm_duty_cycle_update(void)
{
for (int i = 0; i < PHASE_COUNT; i++)
@@ -202,6 +205,16 @@ static void cmd_parser(char *data, uint32_t len)
printf("Notification disabled.\r\n");
}
}
else if (strncmp(data, "test_data:1", 11) == 0)
{
send_daq_enabled = true;
printf("DAQ SPI TX: STARTED (24kHz)\r\n");
}
else if (strncmp(data, "test_data:0", 11) == 0)
{
send_daq_enabled = false;
printf("DAQ SPI TX: STOPPED\r\n");
}
else
{
@@ -247,6 +260,46 @@ int main(void)
printf("%d tick: %d, %d, %d\n", sys_get_tick(), phase[0].duty,
phase[1].duty, phase[2].duty);
}
/* --- DAQ SPI 封包傳輸 (test_data:1 能) --- */
if (send_daq_enabled)
{
DAQ_Packet_t pkt;
/* 封包頭 */
pkt.header = 0x55AA;
/* 時間戳 (單位: us)
* sys_get_tick() 回傳 ms,乘以 1000 轉換成 us */
pkt.timestamp = (uint32_t)(sys_get_tick() * 1000u);
/* 電流: ADC DATA 映射到 i_u, i_v, i_w
* ADC_DATA[0] = U相 (ADC ch6), ADC_DATA[1] = V相 (ADC ch8)
* W 相香用三相平衡對稱推穎: i_w = -(i_u + i_v) */
pkt.i_u = (int16_t)ADC_DATA[0];
pkt.i_v = (int16_t)ADC_DATA[1];
pkt.i_w = (int16_t)(-(ADC_DATA[0] + ADC_DATA[1]));
/* 電壓: 以 duty cycle 對應當前的輸出電壓似真値 */
pkt.v_u = phase[0].duty;
pkt.v_v = phase[1].duty;
pkt.v_w = phase[2].duty;
/* 母線電壓: ADC channel 6 屈
* (若屬於非其他通道,請改為正確的 ADC_DATA 索引) */
pkt.v_bus = (uint16_t)ADC_DATA[0];
/* DDS 參數 */
pkt.dds_ftw = (int32_t)dds.set_dds_ftw;
pkt.dds_amp = (uint32_t)dds.set_dds_amp;
/* 狀態碼: 0 = 正常 */
pkt.error_val = 0;
/* 發送 (CRC16 在函式內自動填充) */
spi_send_daq_packet(&pkt);
}
flag_24Khz_timer = false;
}
#else
@@ -57,7 +57,7 @@
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="4"/>
</listAttribute>
<stringAttribute key="org.eclipse.dsf.launch.MEMORY_BLOCKS" value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;memoryBlockExpressionList context=&quot;Context string&quot;/&gt;&#13;&#10;"/>
<stringAttribute key="org.eclipse.embedcdt.debug.gdbjtag.core.PERIPHERALS" value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;peripherals/&gt;&#13;&#10;"/>
<stringAttribute key="org.eclipse.dsf.launch.MEMORY_BLOCKS" value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;memoryBlockExpressionList context=&quot;Context string&quot;&gt;&#13;&#10; &lt;memoryBlockExpression address=&quot;536874960&quot; label=&quot;&amp;amp;pkt&quot;/&gt;&#13;&#10;&lt;/memoryBlockExpressionList&gt;&#13;&#10;"/>
<stringAttribute key="org.eclipse.embedcdt.debug.gdbjtag.core.PERIPHERALS" value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#13;&#10;&lt;peripherals&gt;&#13;&#10; &lt;peripheral name=&quot;SPI&quot;/&gt;&#13;&#10;&lt;/peripherals&gt;&#13;&#10;"/>
<stringAttribute key="process_factory_id" value="org.eclipse.cdt.dsf.gdb.GdbProcessFactory"/>
</launchConfiguration>
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,47 @@
# SPI DAQ Transmission Feature
This plan outlines the changes needed to support continuous 24kHz transmission of `DAQ_Packet_t` variables via SPI based on the "test_data:" UART command.
## User Review Required
> [!WARNING]
> **SPI Pin Conflict with PWM**: The standard SPI pin mapping configures `PA2`, `PA3`, `PA4`, and `PA5`. However, in your application `init.c`, `PA0` to `PA5` are mapped to Alternative Function 6 (`GPIO_AF_6`) as EPWM output for motor control. Please review and clarify which pins you want to use for the SPI bus. If there are alternate routing mappings or a second SPI interface (`SPI1`), please specify them.
> [!CAUTION]
> **Performance Constraint at 24kHz**: `DAQ_Packet_t` is 34-36 bytes long (depending on packing). Transmitting this much data at 24,000 times per second means pushing an SPI bandwidth of almost 7 Megabits per second (if back-to-back), plus software overhead. If standard polling is used, this could take a significant chunk of time out of the 41.6µs period. Please advise if a high SPI Baudrate or DMA is available/desired.
## Proposed Changes
### [MODIFY] main.c
1. Add global runtime flag: `bool send_daq_enabled = false;`.
2. Extend `cmd_parser` to check `strncmp(data, "test_data:1", 11) == 0` (enable) and `test_data:0` (disable).
3. Inside the `flag_24Khz_timer` loop, populate `DAQ_Packet_t` structure (using actual `timestamp`, `phase` duty values mapped to current/voltage, `dds_amp`, `dds_ftw`, etc.).
4. Send the structure bytes over SPI0 if `send_daq_enabled == true`.
### [MODIFY] main.h
1. Provide the definition of `DAQ_Packet_t`. Ensure it has `#pragma pack(push, 1)` behavior to preserve proper byte alignment for parsing.
### [MODIFY] init.c
1. Create `spi_config(void)` function taking into account the relevant `GPIO_AF_x` mappings and highest reasonably possible `.SPI_BaudRatePrescaler`.
2. Initialize `SPI0` in Master mode.
3. Call `spi_config()` in `SYS_Config()`.
### [MODIFY] init.h
1. Add function prototype for `spi_config()`.
## Open Questions
1. **Which specific GPIO pins** should be configured for the SPI bus mapping to avoid conflict with `EPWM`?
2. **What data** exactly should be mapping into variables like `i_u`, `v_u`, `v_bus`, `error_val` etc? Currently there are `phase[0].duty` and predefined values. Should we mock these fields, leave them as `0`, or link them to specific placeholders?
3. Can we assume **SPI0** in Master mode is perfectly fine for this application?
4. **CRC16 Implementation**: Is the `crc16` field generated by software or a hardware peripheral?
## Verification Plan
### Automated/Code Verification
- Compile code to ensure `DAQ_Packet_t` structures are safely populated and no definitions are missing.
### Manual Verification
- Send `test_data:1` over UART.
- Measure the SPI clock and `MOSI` pin using a logic analyzer to verify data is successfully bursted exactly at the 24kHz rate.
- Parse the resulting values logic analyzer to ensure `DAQ_Packet_t` `crc16` and fields align correctly.