DSP调通磁编码器
MA732GQ-Z带ABZ增量式和PWM输出的14位数字式非接触式角度传感器MA732GQ-Z中文资料_最新报价_数据手册下载_MPS(芯源)-位置传感器-立创商城图1磁编码器原理接线图磁铁贴紧芯片 → reg270x80仅 Bit71红灯亮磁铁拿很远 → reg270x40仅 Bit61绿灯亮找到黄金距离 → reg270x00两灯全灭读取正常1.SPI和SSI两种方式MA732不需要软件复位上电自动从 NVM 加载配置立即可用根据规格书MA732 的 SPI 通信确实分为三种操作模式(SSI 是一种仅用于数据读取的两线同步串行接口。仅支持角度读取。无法使用 SSI 读取或写入寄存器。)模式说明读取角度 (Read Angle)主机拉低 CS 即可无需发送命令MISO 直接输出角度数据读取寄存器 (Read Register)主机需发送 16 位帧命令010 5 位寄存器地址 8 位零写入寄存器 (Write Register)主机需发送 16 位帧命令100 5 位寄存器地址 8 位数据值图2传感器规格书SPI说明2. 1 SPI读取角度图3读取角度MOSI发全0ma732_angle角度值MA732 输出 14bit 角度范围0 ~ 163830x3FFF2.2 SPI读取寄存器需要两个连续的16-bit SPI帧共32个时钟周期。第一帧取回角度第二帧取回寄存器值。图4读取角度需要命令和读取的寄存器地址图5规格书对应的寄存器对应的地址2.3 SPI 时钟模式2种Mode 0 和 Mode 3SPI 模式CPOLCPHASCLK 空闲状态数据捕获数据发送Mode 000低电平SCLK 上升沿SCLK 下降沿Mode 311高电平SCLK 上升沿SCLK 下降沿图6传感器规格书SPI时钟模式选用标准通信为SPI Mode0SCLK 空闲状态低电平数据在 SCLK 上升沿锁存、下降沿移位图7时钟和CS波形图8时钟和mosi波形2.4遇见问题如图可见时钟电压不对解决通过IO模拟增加上拉电阻等仍没有解决但在配置读取寄存器MOSI需要发送命令寄存器地址在示波器可以看到MOSI在时钟下是有正确数据的。读取到010 11011 010为命令11011是1B为寄存器27的值。可见示波器显示的时钟线为2V也可以正常识别到的。图9:证明有驱动3.3.V的能力正常 SPI 模式需要上电瞬间直接跳到接近 3.3V 高电平。和DSP28335 连接初始化SPIA文章后有完整代码MOSI (SPISIMOA), MISO (SPISOMIA), SCLK (SPICLKA), CS(SPISTEA)硬件连接代码都相对简单但在测试的时候MA732 SPI只读出0 / 65535检查接线没有问题信号F28335 引脚MOSI (SPISIMOA)GPIO16MISO (SPISOMIA)GPIO17SCLK (SPICLKA)GPIO18CSGPIO19图9编码器和F28335接线对应图先用SPI回环测试图10根据TI的例程Expressions发送和接收数据没有问题没放磁铁时HL1绿灯亮代表磁场弱MGL1此时 A、B 输出的是非常干净、规整的 3.3V 方波。在磁场有效两个灯都灭时A、B 会变成稳定的高/低电平。2.5 SPI代码未成功不知道是链路有问题还是配置问题角度和寄存器的值只有最大和最小值怀疑是线路浮空或者磁铁问题后续证明磁铁位置没有问题。#include DSP2833x_Device.h#include DSP2833x_Spi.h#include DSP2833x_Device.htypedef unsigned char Uint8;//typedef unsigned int Uint16;//typedef unsigned long Uint32;//简易延时替代DELAY_US#define DELAY_US(n) {Uint32 i;for(i0;i((Uint32)n*150U);i);}// MA732 CS引脚 GPIO19 #define MA732_CS_L() GpioDataRegs.GPACLEAR.bit.GPIO19 1;#define MA732_CS_H() GpioDataRegs.GPASET.bit.GPIO19 1;Uint16 SpiA_WriteRead16(Uint16 txData) //SPI 16 位读写、CS 宏、简易 DELAY_US{while(SpiaRegs.SPISTS.bit.BUFFULL_FLAG 1);SpiaRegs.SPITXBUF txData;while(SpiaRegs.SPISTS.bit.INT_FLAG 0);return SpiaRegs.SPIRXBUF;}Uint8 MA732_ReadRegister(Uint8 regAddr){Uint16 rxData1, rxData2;// 读命令010 5-bit地址 8-bit 0Uint16 txCmd (0x2 13) | ((Uint16)regAddr 8);// 第一帧 MA732_CS_L(); // CS 拉低开始通信DELAY_US(5); // 满足 tScL 80nsrxData1 SpiA_WriteRead16(txCmd); // 发送读命令丢弃返回的 Angle// 注意这里不拉高 CS// 空闲等待 DELAY_US(5); // 必须 750ns这里给 5us 绝对够// 第二帧 rxData2 SpiA_WriteRead16(0x0000); // 发送 0x0000读取寄存器值MA732_CS_H(); // 两帧都发完了再拉高 CSDELAY_US(5);// 返回高 8 位寄存器值return (rxData2 8) 0x00FF;}Uint16 MA732_ReadAngle(void){Uint16 rxData;MA732_CS_L();DELAY_US(5);rxData SpiA_WriteRead16(0x0000); // 直接读MOSI 全 0MA732_CS_H();DELAY_US(5);// 修正MA732 返回 16 位高 14 位是角度低 2 位是 0// F2833x SPI 接收是左对齐所以直接返回即可return rxData 0xFFFC;}void MA732_Spi_Init(void){EALLOW;// CS GPIO19GpioCtrlRegs.GPAMUX2.bit.GPIO19 0;GpioCtrlRegs.GPADIR.bit.GPIO19 1;GpioCtrlRegs.GPAPUD.bit.GPIO19 1;MA732_CS_H();// SPIA 引脚复用GpioCtrlRegs.GPAMUX2.bit.GPIO16 1;GpioCtrlRegs.GPAMUX2.bit.GPIO17 1;GpioCtrlRegs.GPAMUX2.bit.GPIO18 1;// 方向设置GpioCtrlRegs.GPADIR.bit.GPIO16 1; // MOSI 输出GpioCtrlRegs.GPADIR.bit.GPIO17 0; // MISO 输入GpioCtrlRegs.GPADIR.bit.GPIO18 1; // SCLK 输出// 上拉设置SCLK 使能上拉GpioCtrlRegs.GPAPUD.bit.GPIO16 1;GpioCtrlRegs.GPAPUD.bit.GPIO17 1;GpioCtrlRegs.GPAPUD.bit.GPIO18 0;EDIS;SpiaRegs.SPICCR.bit.SPICHAR 15; //16-bit char bitsSpiaRegs.SPICCR.bit.SPILBK 0;SpiaRegs.SPICCR.bit.CLKPOLARITY 0;SpiaRegs.SPICCR.bit.SPISWRESET 0;SpiaRegs.SPICTL.bit.SPIINTENA 0; //Disable SPI INTSpiaRegs.SPICTL.bit.TALK 1; //Enable TXSpiaRegs.SPICTL.bit.MASTER_SLAVE 1; //MaterSpiaRegs.SPICTL.bit.CLK_PHASE 1;SpiaRegs.SPICTL.bit.OVERRUNINTENA 0;//禁用溢出中断SpiaRegs.SPIBRR 36; // SPI Baud Rate LSPCLK/(361)37.5MHz/371MHzSpiaRegs.SPIPRI.bit.FREE 1; // Set so breakpoints dont disturb xmissionSpiaRegs.SPICCR.bit.SPISWRESET 1; // Relinquish SPI from Reset}volatile Uint8 ma732_reg27_value;volatile Uint16 ma732_angle;void main(void){InitSysCtrl();DINT;IER 0x0000;IFR 0x0000;MA732_Spi_Init();for(;;){//SpiA_WriteRead16(0x0000); // 临时测试连续发不要DELAYma732_reg27_value MA732_ReadRegister(0x1B);ma732_angle MA732_ReadAngle();DELAY_US(1000);}}2026.10.19上方SPI代码没有成功读取角度值通过示波器可以检查到CSMOSISCLK都有数据但在MISO数据只有高低3.1 SSI通讯SSI 是一种两线制、同步串行接口仅用于读取数据。传感器在系统中作为外部 SSI 主机的从机工作完整读取 1 个 dummy 时钟 16 个数据时钟 17 个时钟MSB 在第 2 个时钟出现重要提示本传感器实现的 SSI 与标准 SSI 不同因此可能无法与标准 SSI 器件配合工作。本传感器的 SSI 采用 SSCK 低电平空闲而标准协议中 SSCK 采用高电平空闲本传感器要求在一帧 SSI 的起始处于 SSCK 上给出一个哑上升沿dummy rising edge标准 SSI 无此要求。Dummy:主机先发1 个时钟脉冲这个脉冲不输出有效角度数据只是用来触发编码器内部移位寄存器准备数据MSB:Most Significant Bit最高有效位.高位先出下方代码以经过AI和实操认证#include DSP2833x_Device.h#include DSP2833x_Examples.h/* ---------------- 用户可调参数 ---------------- */#define SSI_HALF_CYC 44 /* SCK 半周期: 44 CPU cycles 150MHz 0.29us(要求 0.1us; 改主频时按比例修改) */#define SSI_DEAD_US 45 /* 帧间死区, 要求 40us (t_p) */#define SSI_POLL_US 200 /* 主循环轮询周期 200us 5kHz */#define SSI_MAX_STEP 0x2000 /* 相邻两帧最大合理跳变(16bit): 819245°,超过记一次 glitch, 用于发现位错位/干扰 *//* ---------------- 引脚宏 ---------------- */#define SSI_SCK_H() (GpioDataRegs.GPASET.bit.GPIO18 1)#define SSI_SCK_L() (GpioDataRegs.GPACLEAR.bit.GPIO18 1)#define SSI_DAT() (GpioDataRegs.GPADAT.bit.GPIO17)#define SSI_CS_H() (GpioDataRegs.GPASET.bit.GPIO19 1) /* 仅兼容已接线硬件 *//* 确定延时的半周期: RPT 循环, 每次循环 1 cycle, 不受编译器影响 */#define SSI_STR2(x) #x#define SSI_STR(x) SSI_STR2(x)static inline void SSI_DLY(void){asm( RPT # SSI_STR(SSI_HALF_CYC) || NOP);}/* ---------------- 函数声明 ---------------- */void SSI_GpioInit(void);Uint16 SSI_ReadFrame(void); /* 返回 16 位原始字 (含低 2 位补 0) */Uint16 SSI_ReadAngle(Uint16 *raw16); /* 带校验, 返回 1本次数据可信 */void SSI_CaptureBits(Uint16 nclk); /* 调试: 抓原始比特流 *//* ---------------- 观测变量 (Expressions 窗口直接看) ---------------- */volatile Uint16 ssi_raw; /* 16 位原始字 angle14 2 */volatile Uint16 ssi_angle14; /* 14 位角度 0..16383 */volatile float ssi_deg; /* 角度 0..360 度 */volatile float ssi_speed_dps; /* 角速度 度/s (带符号) */volatile Uint16 ssi_mgl; /* 磁场低于 MGLT 指示 (可选) */volatile Uint16 ssi_mgh; /* 磁场高于 MGHT 指示 (可选) */volatile Uint16 ssi_align_err; /* 低 2 位不为 0 的帧数 (位错位/干扰) */volatile Uint16 ssi_glitch_cnt; /* 相邻帧跳变超限的次数 */volatile Uint16 ssi_ok; /* 最近一帧是否可信 1/0 */volatile Uint16 ssi_bits[34]; /* 调试: 原始比特流 *//******************************************************************************* GPIO 初始化* 要点: 先把输出锁存写低, 再打开方向, 避免上电 SCK 冒出毛刺沿* (MA732 会把第一个上升沿当 dummy, 毛刺会打乱帧对齐)******************************************************************************/void SSI_GpioInit(void){/* 输出锁存先置初值 (不需要 EALLOW) */SSI_SCK_L();SSI_CS_H();EALLOW;SysCtrlRegs.PCLKCR3.bit.GPIOINENCLK 1; /* 不开这个输入永远读到 0 */GpioCtrlRegs.GPAMUX2.bit.GPIO17 0; /* SSD 普通 IO */GpioCtrlRegs.GPAMUX2.bit.GPIO18 0; /* SSCK 普通 IO */GpioCtrlRegs.GPAMUX2.bit.GPIO19 0; /* CS 普通 IO(兼容) */GpioCtrlRegs.GPAMUX2.bit.GPIO20 0; /* MGL 可选 */GpioCtrlRegs.GPAMUX2.bit.GPIO21 0; /* MGH 可选 */GpioCtrlRegs.GPADIR.bit.GPIO17 0; /* 输入 */GpioCtrlRegs.GPADIR.bit.GPIO18 1; /* 输出 */GpioCtrlRegs.GPADIR.bit.GPIO19 1;GpioCtrlRegs.GPADIR.bit.GPIO20 0;GpioCtrlRegs.GPADIR.bit.GPIO21 0;GpioCtrlRegs.GPAPUD.bit.GPIO17 0; /* SSD 上拉 */GpioCtrlRegs.GPAPUD.bit.GPIO20 0;GpioCtrlRegs.GPAPUD.bit.GPIO21 0;EDIS;}/******************************************************************************* 读一帧: 17 个时钟 (1 dummy 16 数据), 上升沿后采样, MSB first* 帧尾 SSCK 保持高 40us (t_p), 再回空闲低******************************************************************************/Uint16 SSI_ReadFrame(void){Uint16 v 0;Uint16 i;Uint16 b;SSI_SCK_L();SSI_DLY(); /* 空闲低保持, 保证下一沿是起始沿 */for (i 0; i 17; i){SSI_SCK_H();SSI_DLY(); /* 上升沿后 0.29us 采样, 远大于 t_ssd15ns */b SSI_DAT() ? 1u : 0u;SSI_SCK_L();SSI_DLY(); /* 低电平 0.29us, 满足 t_ssckL 0.1us */if (i ! 0) /* 跳过第 1 个 dummy 时钟 */{v (Uint16)((v 1) | b);}}SSI_SCK_H(); /* 死区: SSCK 高 40us 后才允许下一帧 */DELAY_US(SSI_DEAD_US);SSI_SCK_L();return v;}/******************************************************************************* 带校验读取* 校验 1: 16 位字低 2 位必须为 0 (14 位数据左对齐补 0), 否则判为错位帧* 校验 2: 与上帧差值(环绕)不得超过 SSI_MAX_STEP* 返回: 1 数据可信, *raw16 有效; 0 本帧丢弃, 沿用上帧******************************************************************************/Uint16 SSI_ReadAngle(Uint16 *raw16){static Uint16 prev 0;static Uint16 have 0;Uint16 raw;Uint16 ok 1;Uint16 diff;int16 d;raw SSI_ReadFrame();/* --- 校验 1: 补 0 位 --- */if ((raw 0x0003u) ! 0u){ssi_align_err;ok 0;}/* --- 校验 2: 跳变检查 (16 位环绕差值) --- */if (have){diff (Uint16)(raw - prev);d (int16)diff;if (d (int16)SSI_MAX_STEP || d -(int16)SSI_MAX_STEP){ssi_glitch_cnt;ok 0;}}if (ok){prev raw;have 1;*raw16 raw;}else{*raw16 prev; /* 不可信时沿用上一帧, 输出不跳变 */}return ok;}/******************************************************************************* 调试: 抓 nclk 个原始比特 (SCK 从空闲低开始打 nclk 个脉冲, 上升沿采样)* 用法: SSI_CaptureBits(34); 在 Expressions 里看 ssi_bits[], 数有效位数******************************************************************************/void SSI_CaptureBits(Uint16 nclk){Uint16 i;if (nclk 34) { nclk 34; }SSI_SCK_L();SSI_DLY();for (i 0; i nclk; i){SSI_SCK_H();SSI_DLY();ssi_bits[i] SSI_DAT() ? 1u : 0u;SSI_SCK_L();SSI_DLY();}SSI_SCK_H();DELAY_US(SSI_DEAD_US);SSI_SCK_L();}/******************************************************************************* main******************************************************************************/void main(void){Uint16 raw;Uint16 ok;int16 d;static Uint16 prev_raw 0;static Uint16 have_prev 0;float dt_s;InitSysCtrl();/* 跑 Flash 时必须打开:MemCopy(RamfuncsLoadStart, RamfuncsLoadEnd, RamfuncsRunStart);InitFlash();*/DINT;IER 0x0000;IFR 0x0000;SSI_GpioInit();/* 预热: 丢掉上电后前几帧 (芯片内部滤波器稳定) */{ Uint16 k; for (k 0; k 10; k) { (void)SSI_ReadFrame(); } }dt_s (float)SSI_POLL_US * 1e-6f;for (;;){ok SSI_ReadAngle(raw);ssi_raw raw;ssi_angle14 (Uint16)(raw 2);ssi_deg (float)ssi_angle14 * (360.0f / 16384.0f);if (have_prev){d (int16)(Uint16)(raw - prev_raw); /* 16 位环绕差值 */ssi_speed_dps (float)d * (360.0f / 65536.0f) / dt_s;}prev_raw raw;have_prev 1;ssi_ok ok;/* 磁场告警 (可选, 接线才有效) */ssi_mgl GpioDataRegs.GPADAT.bit.GPIO20;ssi_mgh GpioDataRegs.GPADAT.bit.GPIO21;DELAY_US(SSI_POLL_US);}}