polarimeter_software/User/board/bsp_collect.c

231 lines
6.3 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* @Author: mypx
* @Description: ADS8866采集-3线模式(TIM3中断驱动)
*/
#include "bsp_collect.h"
#include "bsp_misc.h"
#include "et_log.h"
#include "main.h"
#include "spi.h"
#include "tim.h"
#include <rtthread.h>
#include <stdlib.h>
static uint16_t *g_buffer = NULL;
static uint16_t g_buf_size = 0;
static uint16_t g_target_count = 0; // 目标采集数
static volatile uint16_t g_count = 0; // 已采集数
static dma_full_cb_t g_complete_cb = NULL;
// 3线模式: DIN保持高, CONVST控制转换+片选
#define ADS8866_DIN_HIGH() GPIOB->BSRR = (1u << 15)
#define PB15_AS_GPIO() GPIOB->CRH = (GPIOB->CRH & ~(0xFu << 28)) | (0x3u << 28)
// 延时n个时钟周期每个周期≈13.89ns
static inline void ns_delay(uint32_t cycles)
{
// 关闭编译器优化确保NOP不被删除
__asm volatile("1: SUBS %0, %0, #1\n" // 计数器减1
" BNE 1b" // 若未到0则循环
: "=r"(cycles) // 输出操作数
: "0"(cycles) // 输入操作数
);
}
void delay_100ns(void)
{
ns_delay(7);
}
// 单次读取(在中断里调用,要快速)
static inline uint16_t ads8866_read_once(void)
{
uint16_t rx = 0;
// ADS8866转换时间约3µs, 等待转换完成
// 72MHz系统时钟, 1个NOP约14ns, 300个NOP约4.2µs
for (volatile int i = 0; i < 6; i++)
delay_100ns();
// CONVST回到高电平, 数据就绪, 直接SPI读取
HAL_SPI_Receive(&ADS8866_SPI, (uint8_t *)&rx, 1, 10);
return rx;
}
int bsp_light_data_sampling_init(uint16_t *adc_buf, uint16_t length, dma_full_cb_t cb)
{
g_buffer = adc_buf;
g_buf_size = length;
g_complete_cb = cb;
g_count = 0;
g_target_count = 0;
// 初始化TIM3(产生CONVST), SPI2(读取数据)
MX_TIM3_Init();
MX_SPI2_Init();
__HAL_SPI_ENABLE(&ADS8866_SPI);
// PB15(DIN)配置为GPIO并保持高电平
PB15_AS_GPIO();
ADS8866_DIN_HIGH();
ET_INFO("bsp_collect: init done, buf_size=%u", length);
return 0;
}
// // Shell命令: 启动采集指定数量
// int cstart(int argc, char **argv)
// {
// if (argc < 2)
// {
// rt_kprintf("Usage: cstart <count>\r\n");
// return -1;
// }
// int count = atoi(argv[1]);
// if (count <= 0 || count > g_buf_size)
// {
// rt_kprintf("cstart: invalid count (1~%u)\r\n", g_buf_size);
// return -2;
// }
// if (!g_buffer)
// {
// rt_kprintf("cstart: buffer not init\r\n");
// return -3;
// }
// // 设置目标数量并启动
// g_count = 0;
// g_target_count = count;
// bsp_system_led_on();
// rt_kprintf("cstart: collecting %d samples...\r\n", count);
// // 启动TIM3 PWM + 中断
// HAL_TIM_PWM_Start(&COLLECT_TIM, TIM_CHANNEL_3);
// HAL_TIM_Base_Start_IT(&COLLECT_TIM);
// rt_kprintf("cstart: started (non-blocking)\r\n");
// return 0;
// }
// int cprint(int argc, char **argv)
// {
// uint16_t n = 32;
// if (argc >= 2)
// n = (uint16_t)atoi(argv[1]);
// if (!g_buffer || g_count == 0)
// {
// rt_kprintf("cprint: no data\r\n");
// return -1;
// }
// if (n > g_count)
// n = g_count;
// uint16_t minv = 0xFFFF, maxv = 0;
// uint32_t sum = 0;
// for (uint16_t i = 0; i < g_count; i++)
// {
// uint16_t v = g_buffer[i];
// if (v < minv)
// minv = v;
// if (v > maxv)
// maxv = v;
// sum += v;
// }
// rt_kprintf("cprint: N=%u min=%u max=%u avg=%lu\r\n", g_count, minv, maxv, sum / g_count);
// rt_kprintf("first %u (dec / hex):\r\n", n);
// for (uint16_t i = 0; i < n; i++)
// {
// if (i % 8 == 0)
// rt_kprintf("\r\n[%04u] ", i);
// rt_kprintf("%5u/0x%04X ", g_buffer[i], g_buffer[i]);
// }
// rt_kprintf("\r\n");
// return 0;
// }
// MSH_CMD_EXPORT_ALIAS(cstart, cstart, collect N samples)
// MSH_CMD_EXPORT_ALIAS(cprint, cprint, print data)
// 启动采集: 设置目标数量, 启动TIM3+中断
int bsp_light_data_sampling_start(void)
{
if (!g_buffer || g_buf_size == 0)
{
ET_ERR("bsp_collect: buffer not initialized");
return -1;
}
g_count = 0;
g_target_count = g_buf_size; // 采集满缓冲区
bsp_system_led_on();
// 启动TIM3 PWM(产生CONVST) + Update中断
HAL_TIM_PWM_Start(&COLLECT_TIM, TIM_CHANNEL_3);
HAL_TIM_Base_Start_IT(&COLLECT_TIM);
//ET_INFO("bsp_collect: start, target=%u", g_target_count);
return 0;
}
// 停止采集
int bsp_light_data_sampling_stop(void)
{
HAL_TIM_Base_Stop_IT(&COLLECT_TIM);
HAL_TIM_PWM_Stop(&COLLECT_TIM, TIM_CHANNEL_3);
bsp_system_led_off();
//ET_INFO("bsp_collect: stopped, collected=%u/%u", g_count, g_target_count);
return 0;
}
uint16_t light_raw_map_u16(uint16_t val)
{
/* Avoid integer truncation: do multiply before divide using 32-bit intermediate.
* Map 0..65535 -> 0..4095. Use rounding by adding half-divisor. */
uint32_t tmp = (uint32_t)val * 4095u;
return (uint16_t)(tmp / 65535u + 0.5f);
}
float light_raw_map_f32(uint16_t val)
{
return (float)(val / 65535.0f * 4095.0f);
}
// TIM3中断回调: 每次CONVST触发后采集一个点
void sampling_tim_elapsed_callback(void)
{
// 未启动或已完成
if (g_target_count == 0 || g_count >= g_target_count)
return;
// 读取一个点
if (g_buffer && g_count < g_buf_size)
{
/* drive LED pin high at the start of ISR and low at the end
* so each interrupt produces one pulse. This makes the pulse
* frequency equal to the timer update frequency (no 2x toggle
* ambiguity). */
bsp_system_led_on();
g_buffer[g_count] = light_raw_map_u16(ads8866_read_once());
g_count++;
bsp_system_led_off();
// 达到目标数量, 停止并回调
if (g_count >= g_target_count)
{
HAL_TIM_Base_Stop_IT(&COLLECT_TIM);
HAL_TIM_PWM_Stop(&COLLECT_TIM, TIM_CHANNEL_3);
bsp_system_led_off();
//ET_INFO("bsp_collect: complete, N=%u", g_count);
// 调用完成回调
if (g_complete_cb)
g_complete_cb();
g_target_count = 0; // 标记完成
}
}
}