赞
踩
最近开发28388平台要加上Spi_DAC的功能,总体开发方式采用Simulink代码生成的方式,具体到Spi与DAC芯片通信部分,采用Custom Code外接手写代码的方法实现。
由于组内之前有过用28335开发的Spi_DAC的资源,所以一开始想着移植一下程序应该就能用,只是改了下28388与28335在SpiaRegs与GpioCtrlRegs里名称发生改变的寄存器位和对应发生变化的头文件,第一次修改后的外挂手写移植程序如下:
- #include "f28x_project.h"
- #include "rtwtypes.h"
-
- #define Fs_Set GpioDataRegs.GPBSET.bit.GPIO35 = 1 //FS Pin
- #define Fs_Clr GpioDataRegs.GPBCLEAR.bit.GPIO35 = 1
- #define Load_Set GpioDataRegs.GPBSET.bit.GPIO37 = 1 //Load Pin
- #define Load_Clr GpioDataRegs.GPBCLEAR.bit.GPIO37 = 1
-
- void init_SPI_GPIO(void)
- {
- EALLOW;
- GpioCtrlRegs.GPAPUD.bit.GPIO16=0; //Enables the Pull-up
- GpioCtrlRegs.GPAGMUX2.bit.GPIO16=0; //configure GPIO16 as SPIASIMO
- GpioCtrlRegs.GPAMUX2.bit.GPIO16=1;
-
- GpioCtrlRegs.GPAPUD.bit.GPIO17=0;
- GpioCtrlRegs.GPAGMUX2.bit.GPIO17=0; //configure GPIO17 as SPIASOMI
- GpioCtrlRegs.GPAMUX2.bit.GPIO17=1;
-
- GpioCtrlRegs.GPAPUD.bit.GPIO18=0;
- GpioCtrlRegs.GPAGMUX2.bit.GPIO18=0; //configure GPIO18 as SPISCK
- GpioCtrlRegs.GPAMUX2.bit.GPIO18=1;
-
- GpioCtrlRegs.GPBPUD.bit.GPIO35=0;
- GpioCtrlRegs.GPBGMUX1.bit.GPIO35=0; //configure GPIO35 as GPIO(siganl FS)
- GpioCtrlRegs.GPBMUX1.bit.GPIO35=0;
-
- GpioCtrlRegs.GPBPUD.bit.GPIO37=0;
- GpioCtrlRegs.GPBGMUX1.bit.GPIO37=0; //configure GPIO37 as GPIO(signal LOAD)
- GpioCtrlRegs.GPBMUX1.bit.GPIO37=0;
-
- EDIS;
- }
-
- void init_SPI_A(void)
- {
- EALLOW;
- SpiaRegs.SPICCR.bit.SPISWRESET=0;
-
- SpiaRegs.SPICTL.bit.MASTER_SLAVE=1; //Master Mode
- SpiaRegs.SPICCR.bit.CLKPOLARITY=1;
- SpiaRegs.SPICTL.bit.CLK_PHASE=0;
- SpiaRegs.SPICCR.bit.SPICHAR=15; //16 bit SPI
- SpiaRegs.SPIBRR.bit.SPI_BIT_RATE=39; //Set baud Rate
-
- SpiaRegs.SPICTL.bit.TALK=1; //Enable transmit
- SpiaRegs.SPIPRI.bit.FREE=1;
-
- SpiaRegs.SPICCR.bit.SPISWRESET=1;
- EDIS;
- }
(以上只是初始化代码,transmit data部分的函数没有给出),在simulink中生成整个工程的代码,生成后进入CCS调试。调试时发现无法正常通信,进入单步调试时发现程序进入函数init_SPI_A()后,单步运行函数内的寄存器赋值语句后watch window中寄存器对应位依然位0;无法正常赋值,推测是没有正常初始化,导致无法正常SPI通信。
和C2000Ware(版本3.0.3)中的SPI_loopback程序进行比较,官方程序主函数如下(只放出了初始化程序部分):
- #include "f28x_project.h"
-
- void initSPIFIFO(void);
- void InitSpi(void);
-
- void main(void)
- {
- uint16_t sdata; // sent data
- uint16_t rdata; // received data
-
- InitSysCtrl(); // Initialize device clock and peripherals
-
- DINT; // Disable CPU interrupts
- InitPieCtrl();
- IER = 0x0000;
- IFR = 0x0000;
- InitPieVectTable();
-
- initSPIFIFO(); // Set up SPI, initializing it for FIFO mode
-
- }
-
- void initSPIFIFO(void)
- {
- SpiaRegs.SPIFFTX.all = 0xE040;
- SpiaRegs.SPIFFRX.all = 0x2044;
- SpiaRegs.SPIFFCT.all = 0x0;
-
- InitSpi();
- }
-
- void InitSpi(void)
- {
- SpiaRegs.SPICCR.bit.SPISWRESET = 0;
- SpiaRegs.SPICCR.bit.CLKPOLARITY = 0;
- SpiaRegs.SPICCR.bit.SPICHAR = (16 - 1);
- SpiaRegs.SPICCR.bit.SPILBK = 1;
-
- SpiaRegs.SPICTL.bit.MASTER_SLAVE = 1;
- SpiaRegs.SPICTL.bit.TALK = 1;
- SpiaRegs.SPICTL.bit.CLK_PHASE = 0;
- SpiaRegs.SPICTL.bit.SPIINTENA = 0;
-
- SpiaRegs.SPIBRR.bit.SPI_BIT_RATE = ((50000000 / 1000000) - 1);
-
- SpiaRegs.SPIPRI.bit.FREE = 1;
-
- SpiaRegs.SPICCR.bit.SPISWRESET = 1; // Release the SPI from reset
- }
-
- // End of file
对比可以看到initspi()部分并没有很大的出入。中间还试着在自己的移植程序的初始化函数中试着对EPwm寄存器进行赋值,发现也无法写入。在Ti论坛上发布问题后,大佬指出可能是没有使能spi时钟的原因。然后在上面例程的InitSysCtrl()函数中找到了时钟初始化部分,InitSysCtrl()函数中的InitPeripheralClocks()函数下将CpuSysRegs.PCLKCR8.bit.SPI_A 赋值为1。根据代码注释翻了下28388芯片User Guide,该位是SPI_A时钟的使能位:
很高兴,以为出问题的原因找到了,于是在我移植的初始化程序的第一行加上了例程的InitSysCtrl()函数,相当于使能了SPI时钟。然后点击小锤子,小甲虫,接着单步运行,整个过程行云流水~好的,程序进入spi初始化函数。哈哈,爷真的服了,单步运行完函数中每一句话,watch window中的寄存器位依然为零。不会吧,不会吧,不会三体人真的存在吧?不过watch window中显示CpuSysRegs.PCLKCR8.bit.SPI_A位可以正常写入,运行完语句后该位的value变成了1,应该还有没注意到的地方。
重新梳理一下,之前28335是可以正常通信的,28388如果用搭模块的方法,代码生成也是可以正常通信,能对spi寄存器赋值。有必要将上面两个的工程生成的代码的主函数单步运行仔细看了一下。
28388SPI通信的模型很简单,只有一个SPI模块,如下图所示:
模型生成的代码的主函数部分如下:
- int main(void)
- {
- float modelBaseRate = 0.2;
- float systemClock = 200;
-
- /* Initialize variables */
- stopRequested = false;
- runModel = false;
- c2000_flash_init();
- init_board();
-
- #ifdef MW_EXEC_PROFILER_ON
-
- config_profilerTimer();
-
- #endif
-
- ;
- rtmSetErrorStatus(Spitest_M, 0);
- Spitest_initialize();
- globalInterruptDisable();
- configureTimer0(modelBaseRate, systemClock);
- runModel =
- rtmGetErrorStatus(Spitest_M) == (NULL);
- enableTimer0Interrupt();
- globalInterruptEnable();
- while (runModel) {
- stopRequested = !(
- rtmGetErrorStatus(Spitest_M) == (NULL));
- }
-
- /* Terminate model */
- Spitest_terminate();
- globalInterruptDisable();
- return 0;
- }
init_board()和Spitest_initialize()这两个函数都是初始化;先看了一下Spitest_initialize()函数,这里面大致是simlink自动生成的初始化程序(init_board()初始化函数是Ti的初始化库函数)。单步运行进入Spitest_initialize();根据变量窗口的寄存器变化确定哪一句是初始化函数。最终确定是Spitest_initialize()下的Spitest_SystemCore_setup(&Spitest_DW.obj)下的MW_SPI_Open()函数下的SPI_init()函数,SPI_init()函数使能了Spi时钟,并对引脚进行了配置。这些功能和我加了时钟使能的移植外挂程序没有大的出入。那造成我外挂程序无法赋值的原因应该在init_board()函数中。
进入init_board()函数,不同于官方例程的InitSysCtrl()函数,不同于之前loopback例程的InitPeripheralClocks()函数,这里的init_board()函数只使能了一部分外设时钟,继续向下看有一句:
翻阅28388的芯片User Guide,CPUSEL6寄存器介绍如下图:
可以看到写着“This register must be configured prior to enabling the peripheral clocks.”。再看一下我外挂程序的生成的代码的init_board()函数:
这里的这句代码被条件编译了,不同于搭模型生成的代码文件。但是手册中写着这一位复位值是1,应该默认SPIA是由CPU1控制的呀。再看了下代码,发现上面还有一段代码:
哈哈,这个初始化程序让所有外设一开始都让CPU2在控制....
到这里应该算是破案了,我把DevCfgRegs.CPUSEL6.bit.SPI_A = 0;这句话加到我的手写的初始化函数里。再运行,Debug,这次watch window中寄存器可以正常写入了~轻松秒杀~
最终的初始化程序如下:
- void init_SPI_A(void)
- {
- EALLOW;
- DevCfgRegs.CPUSEL6.bit.SPI_A = 0;
- EDIS;
- InitSysCtrl();
- EALLOW;
- // CpuSysRegs.PCLKCR8.bit.SPI_A = 1;
- SpiaRegs.SPICCR.bit.SPISWRESET=0;
-
- SpiaRegs.SPICTL.bit.MASTER_SLAVE=1; //Master Mode
- SpiaRegs.SPICCR.bit.CLKPOLARITY=1;
- SpiaRegs.SPICTL.bit.CLK_PHASE=0;
- SpiaRegs.SPICCR.bit.SPICHAR=15; //16 bit SPI
- SpiaRegs.SPIBRR.bit.SPI_BIT_RATE=39; //Set baud Rate
-
- SpiaRegs.SPICTL.bit.TALK=1; //Enable transmit
- SpiaRegs.SPIPRI.bit.FREE=1;
-
- SpiaRegs.SPICCR.bit.SPISWRESET=1;
- EDIS;
-
- }
至于为什么在28335上能成功运行,因为28335只有一个核,根本不需要DevCfgRegs这种寄存器来选择是CPU1还是CPU2来控制Spi[doge]。
程序移植后SpiaRegs寄存器无法正常写入的原因:
由于控制器从28335转变为了28388。Simulink针对这两款控制器的代码生成的初始化程序也不一样了。从而导致无法对SpiaRegs赋值。
第一次写博客,写得不清楚的地方多多包涵,也欢迎各位大佬指正!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。