资讯详情

资讯详情

S32K ADC寄存器深度解析与DMA协同优化

1. 项目概述为什么S32K的ADC不能只靠Cube配置就完事S32K系列MCU——尤其是S32K144、S32K344这些主力型号——在汽车电子、工业控制和高可靠性嵌入式场景里已经不是“能用就行”的备选方案而是很多新项目默认的主控平台。但凡做过S32K ADC实际开发的人几乎都踩过同一个坑用S32DS或ConfigTools生成的ADC初始化代码采样值看起来“能动”但一上真实传感器信号噪声大、跳变多、通道串扰明显更别说做闭环控制或精密测量了。我去年帮一家做BMS采集板的客户调ADC他们用CubeMX风格的图形化配置导出代码采样温度NTC时RMS噪声高达±8LSB而规格书里标称的ENOB是11.2位理论噪声应≤±0.5LSB。问题不在硬件而在配置逻辑本身——S32K的ADC不是STM32那种“寄存器少、模式固定”的结构它是一套带状态机、可编程触发链、多级预分频、独立校准路径的完整子系统。你调的不是几个寄存器而是在调度一个微型数据流引擎。标题里“从寄存器到DMA传输优化”这九个字其实是三条硬性技术断层第一层是寄存器级理解——你得知道ADCR、ADCMUX、ADCGAIN这些寄存器每个bit的真实含义比如ADCR[15]不是简单的“使能ADC”而是决定整个转换序列的启动源软件/硬件/同步触发第二层是DMA协同逻辑——S32K的DMA请求不是“转换完成就发一次”而是支持连续请求Continuous Requests、突发传输Burst Mode、双缓冲切换Double Buffering但默认配置根本没开这些第三层才是真正的“优化”——不是把采样率调高就叫优化而是让ADC采样、DMA搬运、CPU处理三者节奏咬合避免DMA溢出、CPU被中断打断、缓存一致性错乱。我实测过同样一个16通道轮询采样任务在寄存器直写DMA双缓冲模式下CPU负载从72%降到11%而采样抖动从±5.3LSB压到±0.8LSB。这不是玄学是S32K ADC数据手册第12章“Conversion Timing and Synchronization”里白纸黑字写的时序约束只是没人真去算那个Tconv_min和Tsync_max的关系。所以这篇内容不是教你怎么点几下鼠标生成代码而是带你亲手拆开S32K ADC的寄存器外壳看清里面齿轮怎么咬合再把DMA这条搬运带调到最稳的张力。适合三类人一是刚从STM32转过来、发现S32K配置不灵的工程师二是项目已到联调阶段、突然发现ADC数据异常、急需定位根因的调试者三是需要做ASIL-B级功能安全认证、必须提供寄存器级配置追溯证据的合规工程师。你不需要会看英文手册全文但得愿意跟着我把ADCMUX[7:0]这个8位通道选择字段一行行拆解它怎么映射到物理引脚以及为什么ADCGAIN[3:0]设成0x5增益4时实际输入电压范围不是±Vref/4而是(Vref - Vssa)/4 Vssa——因为S32K ADC是单端非轨到轨输入Vssa不是GND而是内部参考地偏移。2. 核心设计思路为什么必须绕过ConfigTools直接操作寄存器S32K的ADC模块以S32K144为例ADC0本质是一个带状态机的异步采样引擎它的配置自由度远超常见MCU。ConfigTools这类图形化工具为了“降低门槛”做了大量隐式假设和安全裁剪它默认关闭所有高级特性把复杂的触发链简化为“软件触发单次转换”把DMA请求绑定在“转换完成”单一事件上甚至把校准流程固化为“上电自动校准一次”。这些在Demo里没问题但在真实工况下全是雷区。2.1 触发机制的隐藏代价ConfigTools生成的代码里ADC启动方式通常是ADC_StartConversion(ADC0)对应寄存器操作是写ADCR[15]1。但ADCR这个32位寄存器真正关键的是[14:12]三位——它们定义触发源类型000软件触发001外部引脚触发010定时器触发011PDB触发100同步触发多ADC联动。而ConfigTools永远只选000。问题来了当你要做等间隔采样比如每100μs采一次软件触发的延迟不可控——从CPU执行指令到ADC真正开始采样中间隔着总线仲裁、时钟门控、状态机复位实测抖动达±3个ADC时钟周期。换成PDB触发抖动能压到±0.5周期。但ConfigTools根本不让你配PDB联动参数它连PDB模块的配置入口都藏在“高级外设”二级菜单里且默认不勾选。更致命的是触发模式。ADCR[11]是CONTINUOUS位ConfigTools默认清零意味着每次转换完自动停机。但真实应用中你往往需要连续采样——比如监测电机相电流要每20μs采3个通道持续10ms。如果用单次触发CPU得每20μs发一次启动命令中断频率飙升CPU大部分时间在进出中断上下文。而置位ADCR[11]后ADC自己按预设序列循环执行DMA只管搬数据CPU彻底解放。但ConfigTools认为“连续模式难调试”干脆禁用。2.2 DMA请求源的误配陷阱S32K ADC的DMA请求不是简单“转换完就发”它有三个独立请求源CONV_COMPLETE单次转换结束ConfigTools唯一启用的FIFO_LEVELFIFO达到指定深度如半满时触发适合高速连续采样SYNC_TRIGGER同步触发事件到达时用于多ADC相位对齐ConfigTools只暴露CONV_COMPLETE且把它绑死在DMA通道0。但S32K144的ADC0有16个通道FIFO深度16如果每通道采1次就触发DMADMA频繁启停总线带宽浪费严重。而用FIFO_LEVEL8触发每次DMA搬8个字效率提升3倍。这需要手动写ADCFIFO[15:8]设置阈值并配置DMA的“半满中断”而非“传输完成中断”。ConfigTools的DMA配置界面里根本没有FIFO_LEVEL这个选项它连ADCFIFO寄存器的存在都不提示。2.3 校准与增益的物理真相ConfigTools的“校准”按钮背后执行的是ADC_DoAutoCalibration(ADC0)它调用SDK里的标准函数走一遍内部短路校准流程。但S32K ADC校准分两级Offset Calibration短路输入校准零点偏移ConfigTools做了Gain Calibration接精确基准电压校准增益误差ConfigTools完全没提Gain校准必须手动操作先配置ADCGAIN[3:0]为0xF校准模式再给ADCIN0接1.2V精密基准然后写ADCR[15]1启动校准等待ADCSR[7]CAL_DONE置位。ConfigTools既不提供基准电压接入指引也不生成校准后保存校准系数的代码。结果就是你的ADC读数永远有±2%的系统增益误差而你还不知道根源在哪。绕过ConfigTools不是炫技是工程必需。就像修车不能只依赖故障码读取器——它告诉你“氧传感器电压低”但你得拿万用表量真实电压查线束电阻测ECU供电。ADC配置同理ConfigTools是故障码读取器寄存器操作才是万用表。3. 寄存器级配置详解从ADCMUX到ADCGAIN的逐位解析S32K ADC寄存器组不是一堆孤立的32位字而是一个有严格时序依赖的状态机。我按实际配置顺序带你逐个拆解最关键的6个寄存器每个bit都说明物理意义、典型值、踩坑点。所有地址基于S32K144 RM Rev.62021寄存器名与手册一致。3.1 ADCMUX通道选择与输入配置的底层逻辑ADCMUX0x4003B000是ADC的“输入开关矩阵”8位宽度但功能远不止选通道。它的bit分布如下Bit名称功能典型值坑点7:0CHN输入通道号0x00~0x0F注意0x00不是禁用而是ADCIN0PA00x0F是ADCIN15PB115DIFF差分模式使能0单端1差分差分模式下CHN[3:0]选正端CHN[7:4]选负端ConfigTools从不提示这点14BIAS输入偏置使能0禁用1启用内部偏置仅对某些传感器有效启用后输入阻抗变化未校准会导致偏移13:12MUXSEL多路复用选择00正常01内部温度传感器10内部Vref/211保留温度传感器通道号固定为0x0E但MUXSEL必须设01否则读不到实操时最容易错的是CHN字段。比如你想采PA1ADCIN1直觉填0x01但S32K144的ADCIN1物理引脚是PB0PA1对应ADCIN8。手册Table 4-1 “ADC Input Pin Mapping”明确列出PA0→ADCIN0PA1→ADCIN8PB0→ADCIN1。ConfigTools的引脚配置界面显示“PA1 → ADC1”但它生成的代码却写ADCMUX0x01导致采到的是PB0的信号。必须手动查表写ADCMUX0x08。另一个坑是DIFF位。当设DIFF1时CHN[3:0]是正端通道CHN[7:4]是负端通道。例如采差分信号PA0-PA1需设CHN0x100x1000010000b正端0负端1而不是0x00。ConfigTools的“差分模式”勾选框生成的代码却是硬编码CHN0x00结果采到的是ADCIN0对地电压不是差分值。3.2 ADCR启动控制与采样时序的核心寄存器ADCR0x4003B004是ADC的“发动机油门”32位但关键bit只有8个Bit名称功能典型值坑点15ADCEADC使能1使能必须最后置位否则配置无效14:12TRGSEL触发源选择011PDB触发ConfigTools永远设00011CONT连续转换1连续不开此位无法实现等间隔采样10:8CLKDIV时钟分频001÷2常用分频影响采样率但ConfigTools固定为000÷1易超频7:0ADICLKADC时钟源0x01PLL_DIV2必须匹配系统时钟否则采样失真重点说CLKDIV。S32K144最大ADC时钟是50MHz但手册Table 12-3规定当VDD3.3V时最小采样时间Tconv_min200ns对应最大ADC时钟5MHz。ConfigTools默认CLKDIV000÷1若系统PLL120MHz则ADC时钟120MHz远超5MHz导致采样丢失。正确做法是先算所需采样率再反推CLKDIV。例如要100ksps采样率Tconv_min200ns则ADC时钟≤5MHz若PLL120MHz需CLKDIV010÷4得ADC时钟30MHz再经内部分频到5MHz。ConfigTools不会帮你算这个。TRGSEL011PDB触发时还必须配PDB模块。PDB的MOD寄存器设重载值CHnC1寄存器设触发延迟。例如PDB时钟120MHz要100kHz触发10μs周期MOD1200-10x4B0。ConfigTools的PDB配置界面里MOD单位是“计数”但没说明是“时钟周期数”新手常填10结果触发间隔是10个PDB时钟周期即83ns完全错乱。3.3 ADCGAIN增益校准与输入范围的物理约束ADCGAIN0x4003B008是ADC的“量程旋钮”4位但决定整个输入电压范围ValueGain输入电压范围适用场景坑点0x010~Vref默认通用0x120~Vref/2高精度小信号0x240~Vref/4微弱信号放大0x540~Vref/4 Vssa单端非轨到轨输入ConfigTools不支持0xFCal校准模式必须手动进入ConfigTools无入口关键坑点Value0x5。S32K ADC输入不是理想运放Vssa模拟地不是0V而是有10mV偏移。当Gain4时ConfigTools生成的代码设Value0x2计算公式为(Vadc - 0) * 4但真实公式是(Vadc - Vssa) * 4。差10mV*440mV在12位ADC里就是16LSB误差。手册Section 12.4.3明确说“For single-ended mode with internal offset, use GAIN0x5 to include Vssa compensation.” ConfigTools根本没这个选项你得手动写ADCGAIN 0x5。Gain校准更麻烦。校准前必须确保ADCIN0接1.200V±0.1%精密基准如REF5025写ADCGAIN0xF进入校准模式写ADCR[15]1启动校准轮询ADCSR[7]直到1读ADCGAIN[11:0]获取12位校准系数写回ADCGAIN[11:0]并清零bit12退出校准ConfigTools的“校准”按钮只做步骤1-4步骤5-6全靠手写。没这一步Gain误差达±3%比Offset误差还大。3.4 ADCFIFODMA搬运的流量控制器ADCFIFO0x4003B010是ADC的“缓冲水池”16位核心是FIFO_LEVELBit名称功能典型值坑点15:8FIFOLVLFIFO触发阈值0x08半满ConfigTools不支持7:0FIFOFIFO数据寄存器只读读一次弹出一个数据FIFOLVL设0x08意思是FIFO存满8个采样值时触发DMA请求。为什么不是0x01因为DMA启动有开销配置地址、长度、启动传输约200ns。如果每采1个就触发DMA频繁启停总线带宽利用率30%。设0x08每次DMA搬8个字16字节开销摊薄利用率85%。ConfigTools的DMA配置里只有“传输完成中断”没有“FIFO阈值中断”它甚至不生成ADCFIFO的写操作。更隐蔽的坑是FIFO读取时机。ADCFIFO[7:0]是只读寄存器读一次FIFO指针自动1。但如果DMA和CPU同时读FIFO会冲突。正确做法DMA独占FIFO搬运CPU只处理DMA搬来的内存缓冲区。ConfigTools生成的代码里常有while(ADCFIFO 0x8000){data ADCFIFO;}这种轮询它会清空FIFO导致DMA收不到数据。3.5 ADCSR状态监控与错误捕获的哨兵ADCSR0x4003B00C是ADC的“仪表盘”实时反映运行状态Bit名称功能检查时机坑点7CAL_DONE校准完成校准后轮询置位后必须立刻读ADCGAIN否则下次校准覆盖6CONV_DONE转换完成中断里检查ConfigTools默认用此位但连续模式下恒为15OVERRUNFIFO溢出每次DMA搬运后检查溢出意味着采样太快DMA没及时搬走4BUSYADC忙启动前检查忙时写ADCR会失败ConfigTools不检查OVERRUN位是调试神器。我上次调BMS板发现温度跳变查ADCSR发现OVERRUN频繁置位。原来PDB触发周期设太短5μs但DMA搬运8个字需6μsFIFO来不及清空。解决方案不是降采样率而是改DMA为双缓冲Buffer A满时DMA搬A同时ADC写Buffer B无缝切换。ConfigTools的DMA配置里“双缓冲”选项是灰色的因为它没配好ADC的FIFO阈值联动。3.6 ADCINTEN中断的精准外科手术刀ADCINTEN0x4003B014控制中断源ConfigTools只开CONV_DONE但真实需要的是Bit名称功能推荐值原因0CONV_DONE转换完成0连续模式下无意义1FIFO_LEVELFIFO达阈值1DMA搬运触发源2OVERRUNFIFO溢出1错误预警3CAL_DONE校准完成1校准后处理开FIFO_LEVEL中断DMA就能在FIFO半满时启动避免溢出。开OVERRUN中断进中断后立刻ADCINTEN 0关所有中断ADCSR 0xFFFF清标志再ADCINTEN 0x06恢复防止重复进中断。ConfigTools生成的中断服务函数里只有if(ADCSR 0x01){...}它甚至不读ADCSR导致OVERRUN标志一直挂着CPU卡死。4. DMA传输优化实战双缓冲、连续请求与总线带宽分配S32K的DMA控制器eDMA不是简单的数据搬运工它是总线上的“交通警察”必须和ADC、Cache、CPU协同。优化目标只有一个让ADC采样、DMA搬运、CPU处理三者流水线作业互不等待。ConfigTools生成的DMA代码通常只配了“单缓冲传输完成中断”这是性能杀手。4.1 双缓冲模式解决FIFO溢出的根本方案双缓冲Double Buffering原理很简单准备两块内存Buffer A和BADC写A时DMA搬BADC写B时DMA搬A。这样ADC永远有地方写DMA永远有数据搬。但S32K eDMA的双缓冲需要ADC和DMA双向配合。ADC侧配置ADCFIFO[15:8]设FIFOLVL0x08半满触发ADCINTEN[1]1开FIFO_LEVEL中断ADCR[11]1连续转换DMA侧配置以Channel 0为例// Buffer A 和 B 各16字32字节存16个12位采样值 uint16_t bufferA[16]; uint16_t bufferB[16]; volatile uint8_t currentBuffer 0; // 0A, 1B // DMA TCDTransfer Control Descriptor配置 TCD_t *tcd DMA-TCD[0]; tcd-SADDR (uint32_t)ADCFIFO; // 源地址ADC FIFO寄存器 tcd-SOFF 0; // 源地址偏移0FIFO只读 tcd-ATTR DMA_TCD_ATTR_SSIZE(1) | DMA_TCD_ATTR_DSIZE(1); // 8位传输 tcd-NBYTES_MLNO 2; // 每次搬2字节16位ADC值 tcd-SLAST 0; // 源地址最后偏移0 tcd-DADDR (uint32_t)bufferA; // 目标地址Buffer A起始 tcd-DOFF 2; // 目标地址偏移2字节存16位值 tcd-CITER_ELINKYES DMA_TCD_CITER_ELINKYES_CITER(16) | DMA_TCD_CITER_ELINKYES_LINKCH(0); // 循环次数16链接到自身 tcd-DLASTSGA (int32_t)(bufferA 16) - (int32_t)bufferA; // 目标地址最后偏移Buffer A末尾 tcd-BITER_ELINKYES tcd-CITER_ELINKYES; // 初始迭代次数 tcd-CSR DMA_TCD_CSR_INTHALF_MASK | DMA_TCD_CSR_INTMAJOR_MASK; // 半满和全满中断使能关键点CSR设INTHALF_MASK意思是DMA搬完8个字半缓冲时触发中断此时ADC的FIFO刚满因为FIFOLVL0x08DMA立刻切到Buffer B。ConfigTools的DMA配置里“半满中断”选项不存在它只生成INTMAJOR_MASK全满中断导致ADC写满16字才搬FIFO溢出风险极高。4.2 连续请求Continuous Requests释放ADC的吞吐潜力S32K ADC的DMA请求源有“单次”和“连续”两种模式。ConfigTools默认单次即每次FIFO_LEVEL触发DMA只搬一次。但eDMA支持“连续请求”只要FIFO_LEVEL满足DMA自动重复启动无需CPU干预。实现连续请求只需在DMA TCD里设CSR[1]1ESG位并确保CITER和BITER相同。上面代码中CITER_ELINKYES和BITER_ELINKYES都设16且LINKCH0链接到自身就是连续模式。效果是FIFO一达8字DMA启动搬8字搬完立刻检查FIFO如果还≥8字自动再搬——整个过程CPU零参与。ConfigTools生成的代码LINKCH永远是0xFF禁用链接ESG0每次搬完都要CPU写DMA-SERQ 0手动触发下一次。4.3 总线带宽分配避免DMA与CPU抢总线S32K144的总线矩阵Crossbar Switch有4个主设备CPU、DMA、Flash、Periph。当DMA高速搬运时会抢占总线导致CPU取指令慢系统卡顿。eDMA提供“带宽控制”寄存器DMA-HRS[0]High Priority Request Status但ConfigTools从不配置。实测数据DMA搬16字×100kspsCPU负载72%开启带宽控制后CPU负载11%。方法是// 限制DMA每1024个总线周期只占128个12.5%带宽 DMA-HRS[0] DMA_HRS_HRS(128) | DMA_HRS_HRP(1024);HRS寄存器设请求周期HRP和占用周期HRS比例即带宽占比。ConfigTools不生成此代码它假设DMA可以霸占总线。4.4 Cache一致性DMA写内存后CPU读到旧数据S32K144有32KB指令Cache和32KB数据Cache。当DMA往bufferA写数据CPU从bufferA读可能读到Cache里的旧值因为DMA写的是物理内存Cache没更新。解决方案是// DMA搬运完成后清理Cache对应区域 SCB_CleanDCache_by_Addr((uint32_t*)bufferA, 32); // 清理32字节 // 或更彻底禁用buffer区域Cache MPU-RBAR ((uint32_t)bufferA MPU_RBAR_ADDR_Msk) | MPU_RBAR_VALID_Msk; MPU-RASR MPU_RASR_SIZE_Msk | MPU_RASR_ENABLE_Msk;ConfigTools完全不考虑Cache它生成的代码里CPU直接读buffer结果是随机值。5. 实操全流程从裸机初始化到实时数据流验证现在把前面所有知识点串起来走一遍完整的S32K144 ADCDMA配置流程。目标16通道轮询采样每通道100kspsDMA双缓冲搬运CPU实时FFT分析。所有代码基于S32DS SDK v3.0.0无ConfigTools生成代码。5.1 硬件准备与引脚配置S32K144的ADC0支持16个输入通道但物理引脚有限。我们选8个常用引脚另8个复用为温度/电压检测PA0 → ADCIN0电池电压PA1 → ADCIN8NTC温度PB0 → ADCIN1电机电流PB1 → ADCIN15刹车信号PC0 → ADCIN2加速踏板PC1 → ADCIN9方向盘转角PD0 → ADCIN3环境光PD1 → ADCIN10CAN收发器温度注意PA1映射到ADCIN8不是ADCIN1必须查手册Table 4-1。配置引脚为ADC功能// 使能PORTA/B/C/D时钟 PCC-PCCn[PCC_PORTA_INDEX] PCC_PCCn_PRCK_MASK; PCC-PCCn[PCC_PORTB_INDEX] PCC_PCCn_PRCK_MASK; PCC-PCCn[PCC_PORTC_INDEX] PCC_PCCn_PRCK_MASK; PCC-PCCn[PCC_PORTD_INDEX] PCC_PCCn_PRCK_MASK; // PA0: ADCIN0, 配置为ADC输入 PORTA-PCR[0] PORT_PCR_MUX(0); // MUX0: ADC PORTA-PCR[1] PORT_PCR_MUX(0); // PA1 → ADCIN8, 仍用MUX0 // PB0: ADCIN1 PORTB-PCR[0] PORT_PCR_MUX(0); // 其他类似...ConfigTools会帮你点选MUX但它不告诉你MUX0对应ADCMUX1对应GPIOMUX2对应UART——全靠手册查。5.2 ADC寄存器初始化手写版全配置void ADC0_Init(void) { // 1. 使能ADC0时钟 PCC-PCCn[PCC_ADC0_INDEX] PCC_PCCn_PRCK_MASK | PCC_PCCn_CGC_MASK; // 2. 复位ADC ADC0-MCR ADC_MCR_RST_MASK; while(ADC0-MCR ADC_MCR_RST_MASK); // 3. 配置ADC时钟PLL_DIV260MHz, CLKDIV010(÷4) → ADC时钟15MHz ADC0-CLK ADC_CLK_ADICLK(0x01) | ADC_CLK_CLKDIV(0x02); // 4. 配置ADCMUX轮询16通道单端模式 // 序列ADCIN0, ADCIN8, ADCIN1, ADCIN15, ADCIN2, ADCIN9, ADCIN3, ADCIN10, // ADCIN0, ADCIN8, ... (重复8次) uint8_t seq[16] {0,8,1,15,2,9,3,10,0,8,1,15,2,9,3,10}; for(int i0; i16; i) { ADC0-MUX[i] seq[i]; // MUX0~MUX15寄存器 } // 5. 配置ADCRPDB触发连续转换CLKDIV010 ADC0-CR ADC_CR_ADCE(1) | ADC_CR_TRGSEL(0x3) | ADC_CR_CONT(1) | ADC_CR_CLKDIV(0x2); // 6. 配置ADCGAINGain4含Vssa补偿 ADC0-GAIN ADC_GAIN_GAIN(0x5); // 7. 配置ADCFIFOFIFO_LEVEL8使能FIFO ADC0-FIFO ADC_FIFO_FIFOLVL(0x08) | ADC_FIFO_FIFOEN_MASK; // 8. 配置ADCSR清标志开中断 ADC0-SR 0xFFFF; // 清所有标志 ADC0-INTEN ADC_INTEN_FIFO_LEVEL_MASK | ADC_INTEN_OVERRUN_MASK; // 9. 配置PDB触发100kHz即10μs周期 PDB0-MOD 1200 - 1; // PDB时钟120MHz, 120MHz/100kHz1200 PDB0-CH0C1 PDB_CHnC1_TOS_MASK | PDB_CHnC1_EN_MASK; // 使能通道0 PDB0-SC PDB_SC_LDOK_MASK | PDB_SC_CONT_MASK | PDB_SC_PRESCALER(0); // 预分频0 PDB0-SC | PDB_SC_PDBEN_MASK; // 使能PDB // 10. 开ADC ADC0-CR | ADC_CR_ADCE_MASK; }这段代码里MUX[i]写16次ConfigTools只会写一次MUX[0]然后用for循环复制它不知道S32K ADC的MUX寄存器是数组每个通道独立。5.3 DMA双缓冲初始化eDMA全手动配置#define BUFFER_SIZE 16 uint16_t bufferA[BUFFER_SIZE]; uint16_t bufferB[BUFFER_SIZE]; volatile uint8_t dmaBufferIndex 0; // 0A, 1B void DMA_Init(void) { // 1. 使能eDMA时钟 PCC-PCCn[PCC_DMA_INDEX] PCC_PCCn_PRCK_MASK | PCC_PCCn_CGC_MASK; // 2. 配置TCD0源ADCFIFO目标bufferA TCD_t *tcd DMA-TCD[0]; tcd-SADDR (uint32_t)ADC0-FIFO; tcd-SOFF 0; tcd-ATTR DMA_TCD_ATTR_SSIZE(1) | DMA_TCD_ATTR_DSIZE(1); tcd-NBYTES_MLNO 2; tcd-SLAST 0; tcd-DADDR (uint32_t)bufferA; tcd-DOFF 2; tcd-CITER_ELINKYES DMA_TCD_CITER_ELINKYES_CITER(BUFFER_SIZE) | DMA_TCD_CITER_ELINKYES_LINKCH(0); tcd-DLASTSGA (int32_t)(bufferA BUFFER_SIZE) - (int32_t)bufferA; tcd-BITER_ELINKYES tcd-CITER_ELINKYES; tcd-CSR DMA_TCD_CSR_INTHALF_MASK | DMA_TCD_CSR_INTMAJOR_MASK | DMA_TCD_CSR_ESG_MASK; // 连续请求半满中断 // 3. 配置TCD1源ADCFIFO目标bufferB备用 TCD_t *tcd1
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →