概述
Matlab生成dsp程序——官方例程学习(2)
- 一、主要功能
- 二、CAN总线
- 三、2837x关于CAN说明
- 四、生成程序
- 五、总结
这次学习的是官方例程中的Asynchronous Scheduling,emm因为我也是一边学习一边记录,所以现在也没办法解释整个框架的结构啥的。后面我会一步一步看,慢慢分析的。
例子官网链接:官网例程链接
模型程序链接:模型+程序
一、主要功能
定时器或ePWM模块用于配置定时器中断。定时器中断是根据定时器周期触发的,当收到消息时会触发eCAN消息接收中断。硬件中断块(图中的蓝色模块)触发定时器中断以及eCAN消息接收中断的中断服务程序(ISR)。ISR依次调用连接到硬件中断模块输出端口的功能调用子系统。
前两个子系统的输出是自由运行的计数器。计数器的总和用于控制F2812的PWMB或F2808 / F28335的ePWM2的占空比。PWM波形占空比从0到100%线性增加。
第三个子系统包含一个eCAN接收模块,其消息输出控制PWM模块的占空比(F2812为PWMA或F2808 / F28335为ePWM1)。占空比从0到100%不等,因为从eCAN发送模块接收到eCAN消息。
注意:启用eCAN_A 的回环模式(自发自收)可以在内部连接eCAN_A发送器和接收器,以避免在发送器和接收器之间进行外部连接。要禁用eCAN_A 的回环模式,发送器和接收器必须在外部连接在一起____________以上部分来自官方说明
因为CAN的知识有点遗忘,这里补一下课。
二、CAN总线
帧种类:1.数据帧2.遥控帧3.错误帧4.过载帧5.间隔帧
1.数据帧:用于发送单元向接收单元传送数据的帧。
2.遥控帧:用于接收单元向具有相同ID的发送单元请求数据的帧。
3.错误帧:用于当检测出错误时,向其他单元通知错误的帧。
4.过载帧:用于接收单元通知其尚未做好接收准备的帧。
5.间隔帧:用于数据帧及遥控帧与前面的帧分离开来的帧。
其中,数据帧与遥控帧有标准格式(11个标识符[ID])与扩展格式(29个标识符[ID])两种格式。因为实际中使用的数据帧过程最多,这里着重看看数据帧。
数据段一共由七个段组成:①帧起始②仲裁段③控制段④数据段(最多传送8个字节)⑤CRC段⑥ACK段⑦帧结束
**帧起始:**一个显性电平表示帧起始
仲裁段:
I、标准格式:11位基本ID+RTR(远程请求位[0:数据帧,1:远程帧])
II、扩展格式:11位基本ID+SRR(替代远程请求位[设置为1])+IDE(标识符选择位[0:标准标识符,1:扩展标识符])+18位扩展ID +RTR(远程请求位[0:数据帧,1:远程帧])
控制段:
I、标准格式:IDE(标识符选择位[0:标准标识符,1:扩展标识符])+r0(保留位)+DLC(数据长度/字节)
II、扩展格式:r0(保留位)+r1(保留位)+DLC(数据长度/字节)
**数据段:**8个字节,两种帧格式完全一样。
**CRC段:**15个CRC+一位CRC界定符
**ACK段:**ACK槽+ACK界定符(发送单元:发送2个隐性位,接收单元:接收正确消息-ACK槽发送显性)
**帧结束:**七个位隐性位组成
仲裁手段:1.总线空闲时,最先发送的单元具有优先级2.多个单元同时发送时,连续输出显性电平(逻辑0)多的单元(从ID位进行比较,直到RTR与SRR等位),具有最高优先级。
波特率设置:1位分为4个段(同步段(SS)、传播时间段(PTS)、相位缓冲段1(PBS1)、相位缓冲段2(PBS2)),每个段分为若干个Tq,这称为位时序。位时间=1/波特率。
- 1.同步段(SS):1Tq,多个单元进行同步工作的段。
- 2.传播时间段(PTS):1~8Tq,用于吸收网络上的物理延迟的段。
- 3.相位缓冲段1(PBS1)与相位缓冲段2(PBS2):可对同步端进行补偿(1-8Tq,2-8Tq)[STM32中PTS+PBS1合称BS1]
- 4.再同步补偿宽度(SJW):1-4Tq
三、2837x关于CAN说明
1.操作模式
-
初始化模式(Initialization)
i、可以通过软件(将CAN_CTL寄存器中的Init位置1)、硬件复位或者总线断开进入。当Init置1时,传送停止,输出一直为高。
ii、进入初始化状态后,可以配置波特率与哪些message—box被使用等信息,清除Init位可以结束初始化模式
-
CAN传输模式(正常工作模式)[**CAN Message Transfer (Normal Operation) **]
i、初始化完成后,当Init重新回到0时,便会自动进入此模式。若消息通过过滤则会保存到RAM中。
-
禁用自动重发模式[Disabled Automatic Retransmission ]
i、默认状态下,此模式开启,可以通过CAN Control register 中的DAR位进行关闭。
-
自动总线开启模式[Auto-Bus-On]
i、当开启此功能,可以通过复位Init位,使总线重新开启。
ii、通过使能ABO位,自动总线开启功能将开启。
-
测试模式[Test Modes]
i、上图可以看出测试模式的进入寄存器位设置,其中CAN Control register 中的Test bit必须设置为1,才能使能CAN_TEST模式。
-
静默模式(总线监听模式)[Silent Mode]
i、通过CAN_TEST寄存器中的Silent位进行使能,只接收消息。发送端一直发送隐性(1)电平。
-
回环模式[Loopback Mode]
i、数据将从发送给外部,但是外部信息无法进入内核。其发送的消息直接用内核的TX传送到RX。相当于禁止了外部消息的接收。
-
外部回环模式[**External Loopback Mode **]
i、同回环模式不同的是,外部回环连接到了CAN_TX管脚,可以测试I/O管脚的功能。通过控制ExL等于1开启此模式。
-
回环模式与静默模式一起开启[Loopback Combined with Silent Mode]
i、设置LBack和Silent可以进入此模式。
2.时钟来源:i、外部时钟。ii、系统时钟。iii、GPIO辅助时钟
3.中断功能:通过设置IE0与IE1可以使能CAN0INT与CAN1INT。CAN模块可以响应三种中断:i、消息中断。ii、状态改变中断。iii、错误中断。中断源通过Int0lD/Int1lD进行区分。消息中断的优先级与消息邮箱编号有关,1有最高优先级。中断需要在CAN_GLB_INT_EN register 中启用,处理中断时,必须先清除消息或者状态改变标志,然后进行应答。(via CAN_GLB_INT_CLR and PIEACK )
消息中断:IntPND, TxIE and RxIE (Interrupt Multiplexer register )可以触发CAN0INT与CAN1INT
状态改变中断:RxOk, TxOk, and LEC (Error and Status register )可以触发CAN0INT[需要使能SIE位]
错误中断:PER, BOff and EWarn 可以触发CAN0INT[需要使能EIE位]
四、生成程序
程序框架相对于第一个程序没有很大的变化,
#include "c2807x_2837xx_asyncscheduling_ert.h"
#include "rtwtypes.h"
volatile int IsrOverrun = 0;
static boolean_T OverrunFlag = 0;
void rt_OneStep(void)
{
/* Check for overrun. Protect OverrunFlag against preemption */
if (OverrunFlag++) {
IsrOverrun = 1;
OverrunFlag--;
return;
}
enableTimer0Interrupt();
c2807x_2837xx_asyncscheduling_ert_step();
/* Get model outputs here */
disableTimer0Interrupt();
OverrunFlag--;
}
volatile boolean_T stopRequested = false;
volatile boolean_T runModel = false;
int main(void)
{
float modelBaseRate = 0.001;
float systemClock = 200;
/* Initialize variables */
stopRequested = false;
runModel = false;
c2000_flash_init();
init_board();
#ifdef MW_EXEC_PROFILER_ON
config_profilerTimer();
#endif
;
rtmSetErrorStatus(c2807x_2837xx_asyncschedulin_M, 0);
c2807x_2837xx_asyncscheduling_ert_initialize();
configureTimer0(modelBaseRate, systemClock);
runModel =
rtmGetErrorStatus(c2807x_2837xx_asyncschedulin_M) == (NULL);
enableTimer0Interrupt();
enable_interrupts(); //开启ePWM3/4以及CAN接收中断
globalInterruptEnable();
while (runModel) {
stopRequested = !(
rtmGetErrorStatus(c2807x_2837xx_asyncschedulin_M) == (NULL));
}
/* Disable rt_OneStep() here */
/* Terminate model */
c2807x_2837xx_asyncscheduling_ert_terminate();
globalInterruptDisable();
return 0;
}
/*
* File trailer for generated code.
*
* [EOF]
*/
仍旧是在主函数完成硬件的初始化:c2807x_2837xx_asyncscheduling_ert_initialize(),
设置Timer0作为步长的解算器:configureTimer0(modelBaseRate, systemClock),
每经过一次步长进入Timer0中断函数进行执行:rt_OneStep()
**c2807x_2837xx_asyncscheduling_ert_initialize()**中完成有关外设的初始化:
1.CAN接收的初始化(1.使能接收中断2.使能mailbox1作为接收邮箱)
tCANMsgObject sRXCANMessage;
unsigned char ucRXMsgData[8]= { 0, 0, 0, 0, 0, 0, 0, 0 };
sRXCANMessage.ui32MsgID = 455; // CAN message ID
sRXCANMessage.ui32MsgIDMask = 0; // no mask needed for TX
sRXCANMessage.ui32Flags = MSG_OBJ_RX_INT_ENABLE;
sRXCANMessage.ui32MsgLen = sizeof(ucRXMsgData);// size of message is 4
sRXCANMessage.pucMsgData = ucRXMsgData;// ptr to message content
// Setup the message object being used to receive messages
CANMessageSet(CANA_BASE, 1, &sRXCANMessage, MSG_OBJ_TYPE_RX);
2.ePWM1模块初始化接收eCAN传送来的信息改变占空比。
3.ePWM2模块初始化接收ePWM3和ePWM4送来的信息改变占空比。
4.存储有关的参数进入系统结构体中,参数都是模块的参数。
Timer0中断函数中:
1.开启TIimer0中断(PIE1.7)、开启ePWM3、ePWM4中断。(PIE3.3、PIE3.4)
2.执行**c2807x_2837xx_asyncscheduling_ert_step()**函数:
1)因为程序中存在一个缓冲模块,这里通过一个数组进行缓存。Rate Transfer模块左侧是100k每秒改变一次的数值,右侧的add模块为1K做一次加法。程序中采用了一个数组进行缓存数据。
2)将两个缓存的模块输出直接进行相加后,赋值给ePWM2的CMPA模块
3)eCAN传送的数据的完成自加1后返回(为下一次传送+1数据做准备)
还有三个中断函数内容没有看,分别是ePWM3/4中断和eCANA接收中断:(这三个中断服务函数都在MW_c28xx_csl
.c文件中)。
ePWM3的中断函数:**EPWM3_INT_isr()**函数:
void isr_int3pie3_task_fcn(void)
{
/* Call the system: <Root>/Function-Call Subsystem */
{
/* S-Function (c28xisr_c2000): '<Root>/C28x Hardware Interrupt' */
/* Output and update for function-call system: '<Root>/Function-Call Subsystem' */
{
uint16_T rtb_FixPtSum1;
/* UnitDelay: '<S7>/Output' */
c2807x_2837xx_asyncscheduling_B.Output_f =
c2807x_2837xx_asyncschedulin_DW.Output_DSTATE_g;
/* Sum: '<S8>/FixPt Sum1' incorporates:
* Constant: '<S8>/FixPt Constant'
*/
rtb_FixPtSum1 = (c2807x_2837xx_asyncscheduling_B.Output_f +
c2807x_2837xx_asyncscheduling_P.FixPtConstant_Value) &
8191U; //8191=0x1FFF;
/* Switch: '<S9>/FixPt Switch' */
if (rtb_FixPtSum1 > c2807x_2837xx_asyncscheduling_P.WrapToZero_Threshold)
{
/* Update for UnitDelay: '<S7>/Output' incorporates:
* Constant: '<S9>/Constant'
*/
c2807x_2837xx_asyncschedulin_DW.Output_DSTATE_g =
c2807x_2837xx_asyncscheduling_P.Constant_Value;
} else {
/* Update for UnitDelay: '<S7>/Output' */
c2807x_2837xx_asyncschedulin_DW.Output_DSTATE_g = rtb_FixPtSum1;
}
/* End of Switch: '<S9>/FixPt Switch' */
}
/* End of Outputs for S-Function (c28xisr_c2000): '<Root>/C28x Hardware Interrupt' */
/* Update for RateTransition: '<Root>/Rate Transition' */
c2807x_2837xx_asyncschedulin_DW.RateTransition_Buffer[c2807x_2837xx_asyncschedulin_DW.RateTransition_ActiveBufIdx
== 0] = c2807x_2837xx_asyncscheduling_B.Output_f;
c2807x_2837xx_asyncschedulin_DW.RateTransition_ActiveBufIdx =
(c2807x_2837xx_asyncschedulin_DW.RateTransition_ActiveBufIdx == 0);//让缓冲地址在0-1之间循环
}
}
生成的每个数字每进入一次中断自加1(0-8191之间循环),然后更新缓冲模块。
ePWM4的中断函数:**EPWM4_INT_isr()**函数:与ePWM3生成函数雷同,但是运行范围在0-16383之间。
void isr_int3pie4_task_fcn(void)
{
/* Call the system: <Root>/Function-Call Subsystem1 */
{
/* S-Function (c28xisr_c2000): '<Root>/C28x Hardware Interrupt' */
/* Output and update for function-call system: '<Root>/Function-Call Subsystem1' */
{
uint16_T rtb_FixPtSum1;
/* UnitDelay: '<S10>/Output' */
c2807x_2837xx_asyncscheduling_B.Output_i =
c2807x_2837xx_asyncschedulin_DW.Output_DSTATE_n;
/* Sum: '<S11>/FixPt Sum1' incorporates:
* Constant: '<S11>/FixPt Constant'
*/
rtb_FixPtSum1 = (c2807x_2837xx_asyncscheduling_B.Output_i +
c2807x_2837xx_asyncscheduling_P.FixPtConstant_Value_i) &
16383U;
/* Switch: '<S12>/FixPt Switch' */
if (rtb_FixPtSum1 > c2807x_2837xx_asyncscheduling_P.WrapToZero_Threshold_e)
{
/* Update for UnitDelay: '<S10>/Output' incorporates:
* Constant: '<S12>/Constant'
*/
c2807x_2837xx_asyncschedulin_DW.Output_DSTATE_n =
c2807x_2837xx_asyncscheduling_P.Constant_Value_p;
} else {
/* Update for UnitDelay: '<S10>/Output' */
c2807x_2837xx_asyncschedulin_DW.Output_DSTATE_n = rtb_FixPtSum1;
}
/* End of Switch: '<S12>/FixPt Switch' */
}
/* End of Outputs for S-Function (c28xisr_c2000): '<Root>/C28x Hardware Interrupt' */
/* Update for RateTransition: '<Root>/Rate Transition1' */
c2807x_2837xx_asyncschedulin_DW.RateTransition1_Buffer[c2807x_2837xx_asyncschedulin_DW.RateTransition1_ActiveBufIdx
== 0] = c2807x_2837xx_asyncscheduling_B.Output_i;
c2807x_2837xx_asyncschedulin_DW.RateTransition1_ActiveBufIdx =
(c2807x_2837xx_asyncschedulin_DW.RateTransition1_ActiveBufIdx == 0);
}
}
CAN接收中断函数:CANA0_INT_isr():
void isr_int9pie5_task_fcn(void)
{
/* Call the system: <Root>/Function-Call Subsystem2 */
{
/* S-Function (c28xisr_c2000): '<Root>/C28x Hardware Interrupt' */
/* Output and update for function-call system: '<Root>/Function-Call Subsystem2' */
/* S-Function (c280xcanrcv): '<S3>/eCAN Receive' */
{
tCANMsgObject sRXCANMessage;
unsigned char ucRXMsgData[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
sRXCANMessage.ui32MsgID = 455; // CAN message ID
sRXCANMessage.ui32MsgIDMask = 0; // no mask needed for TX
sRXCANMessage.ui32Flags = MSG_OBJ_RX_INT_ENABLE;
sRXCANMessage.ui32MsgLen = sizeof(ucRXMsgData);// size of message
sRXCANMessage.pucMsgData = ucRXMsgData;// ptr to message content
// Get the receive message
CANMessageGet(CANA_BASE, 1, &sRXCANMessage, false);
if (sRXCANMessage.ui32MsgLen > 0) {
c2807x_2837xx_asyncscheduling_B.eCANReceive_o2[0] = ucRXMsgData[0] |
(ucRXMsgData[1] << 8);
c2807x_2837xx_asyncscheduling_B.eCANReceive_o2[1] = ucRXMsgData[2] |
(ucRXMsgData[3] << 8);
c2807x_2837xx_asyncscheduling_B.eCANReceive_o2[2] = ucRXMsgData[4] |
(ucRXMsgData[5] << 8);
c2807x_2837xx_asyncscheduling_B.eCANReceive_o2[3] = ucRXMsgData[6] |
(ucRXMsgData[7] << 8);
/* -- Call CAN RX Fcn-Call_0 -- */
}
}
/* S-Function (c2802xpwm): '<S3>/ePWM1' */
/*-- Update CMPA value for ePWM1 --*/
{
EPwm1Regs.CMPA.bit.CMPA = (uint16_T)
(c2807x_2837xx_asyncscheduling_B.eCANReceive_o2[0]);
}
/* End of Outputs for S-Function (c28xisr_c2000): '<Root>/C28x Hardware Interrupt' */
}
}
CAN接收中断实现了读取CAN的数据内容,然后进行拼接(CAN接收是按8位进行接收,CMPA是16位寄存器,所以两个8位数据进行拼接变成Uint16)赋给CMPA。
五、总结
可以发现,Simulink生成的函数,框架结构非常严格,可能这就是代码生成的特点把。基本上框架搭好之后,对每个部分重新填充便是一个新的功能函数,代码移植效率也很高。但是机器还是有缺点的,程序可读性没有那么高。再就是报错的时候一脸懵逼,代码生成的报错都是一堆一堆,有点找不到头绪。这两个例子大致是明白了代码工作的情况,下一步准备再多看几个例子多熟悉一下各个库器件。
最后
以上就是危机紫菜为你收集整理的Matlab生成dsp程序——官方例程学习(2)的全部内容,希望文章能够帮你解决Matlab生成dsp程序——官方例程学习(2)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复