TMS320F28388D使用sysconfig配置IPC
第1章 配置IPC底层代码
使用IPC的动机:
我计划我的项目中要使用RS485,CANFD通信和EtherCAT通信,由于通信种类较多,而对于电机控制来说大部分数据都是重复的,并且有些数据可以很久才改变一次,所以我计划使用CPU2做FOC算法控制电机,使用CPU1与上位机进行通信,使用IPC做电机参数之间的通信。
实现目的:
CPU1与CPU2之间可以相互发送数据,数据支持浮点数。通信速度尽可能快和稳定。
下面的代码只有几百行,但是网上资料较少,问了TI工程师也没有答复,整了两三天才整出来,制作不易,希望点赞收藏加个关注,后期会不定时更新单片机的学习笔记。
1.1 CPU1的sysconfig配置
我的CPU1主要是用来做通信的,其实做通信最好是使用CM核,因为他是cortex-M内核,对信息的接收比较好,但是由于网上对这个核的资料很少,并且不能使用sysconfig进行配置,开发速度比较慢,综合起来就使用了CPU1做通信,CPU2做其他外设的控制代码,去跑算法。我的想法是使用CPU1能够主动发送和读取CPU2的数据,CPU2是跑算法和其他外设控制的,所以CPU1的IPC不需要被CPU2的中断,CPU2的数据应能够被CPU1中断。但是看很多解释以及芯片手册,貌似必须要有IPC中断才能接收数据,这点现在依然有疑问。知道的伙伴还望解答。
CPU1的sysconfig配置为:
第一行配置为选择CPU2的boot Mode即启动模式,Sysconfig对其的解释为在FLASH启动,配置完成后仍然需要在CPU1主函数中调用
Device_bootCPU2(BOOT_MODE_CPU2);函数来使能CPU2.
第二行配置为选择IPC的FLAG,CPU的IPC一共有32个标志,这里使用了IPC_FLAG0用作通信触发CPU2的中断,使用IPC_FLAG31来作为标志来同步两个CPU时钟。
第三行配置为选择能使CPU1的IPC_FLAG0,必须要勾选下面的对号,用来触发CPU2的接收中断。
第四行配置为使能IPC_FLAG31来作为标志来同步两个CPU时钟。可以选测0~31任一。
第五行配置为CPU1接收CPU2的IPC触发中断,IPC的中断有IPC0-3四个,这里选择了IPC1,也可使用IPC0,IPC1,IPC2,IPC3。
第六行配置为使能PIE里对应的中断。
1.2 CPU2的sysconfig配置
CPU2的sysconfig配置为
第一行配置为使用了IPC_FLAG1,IPC_FLAG31。
第二行配置为使能IPC_FLAG1,用于配置触发CPU1接收IPC中断的FLAG。
第三行配置为使能IPC_FLAG31,用于同步CPU核的时钟,可用其他FLAG,但要与CPU1的对应。
第四行配置为打开CPU2的IPC0中断,用于触发接收CPU1通过IPC_FLAG0发送的数据的中断
第五行为开启IPC0中断函数
第2章 IPC的应用层代码
2.1 CPU1的主函数IPC代码
第一步:根据1.1的介绍,需要先执行开启CPU2的代码,即:
Device_bootCPU2(BOOT_MODE_CPU2);
第二步:清除IPC标志位,通过IPC_FLAG31同步两个CPU时钟,代码如下
IPC_clearFlagLtoR(IPC_CPU1_L_CPU2_R, IPC_FLAG_ALL);//清除IPC的所有标志位IPC_sync(IPC_CPU1_L_CPU2_R, IPC_FLAG31);//通过IPC_FLAG31同步两个CPU时钟
第一行解释为:清除CPU1与CPU2通信的IPC的所有FLAG。
第二行解释为:同步CPU时钟代码。
第三步:设置要发送的信息,代码为下:
#pragma DATA_SECTION(readData,"MSGRAM_CPU1_TO_CPU2")
float readData[10];
int i,j;
for(i=0; i<10; i++)
{j++;readData[i] = i + j*0.5f;
}
第一行解释为:是 TI 编译器的一条 编译指令(pragma 指令),用于将变量 readData
放入指定的内存段 "MSGRAM_CPU1_TO_CPU2"
中,而不是默认的数据段(如 .data
、.bss
)
地址在:
MEMORY
{CPU1TOCPU2RAM : origin = 0x03A000, length = 0x000800CPU2TOCPU1RAM : origin = 0x03B000, length = 0x000800}SECTIONS
{MSGRAM_CPU1_TO_CPU2 : > CPU1TOCPU2RAM, type=NOINITMSGRAM_CPU2_TO_CPU1 : > CPU2TOCPU1RAM, type=NOINIT}
第二行解释位:定义数据类型,定义为了一个数组。
第三,四,五行解释为:对数据进行初始化。
第四步:发送数据
while(1)
{DEVICE_DELAY_US(5000000);IPC_sendCommand(IPC_CPU1_L_CPU2_R, IPC_FLAG0, IPC_ADDR_CORRECTION_ENABLE,IPC_CMD_READ_MEM, (uint32_t)readData, 10);for(i=0; i<10; i++){j++;readData[i] = i + j*0.5f;}
}
延迟是为了防止数据发送较快,看不出效果,IPC_sendCommand函数中为要发送的数据,数据使用了地址修正功能,
为对数据发送没有影响,可以理解为对数据的功能进行标定,方便对数据进行存储,处理。
CPU1主函数总代码为:
#include "driverlib.h"
#include "device.h"
#include "board.h"
#include "IPC.h"
#include "stdio.h"
#include "Interrupt.h"
#include "string.h"
#include "Modbus.h"
#pragma DATA_SECTION(readData,"MSGRAM_CPU1_TO_CPU2")
float readData[10];
int i,j;
void main(void)
{Device_init();//初始化所有时钟以及外设Interrupt_initModule();//初始化PIE,清除所有PIE寄存器,失能CPU中断Interrupt_initVectorTable();//初始化PIE向量表Board_init();//初始化来自SysConfig的配置Device_bootCPU2(BOOT_MODE_CPU2);//启动CPU2核心部分TX_EN;//RS485发送信息使能IPC_clearFlagLtoR(IPC_CPU1_L_CPU2_R, IPC_FLAG_ALL);//清除IPC的所有标志位IPC_sync(IPC_CPU1_L_CPU2_R, IPC_FLAG31);//通过IPC_FLAG31同步两个CPU时钟EINT;//使能全部中断ERTM;//使能允许调试setvbuf(stdout, NULL, _IONBF, 0);//防止发送堵塞while(1){DEVICE_DELAY_US(5000000);IPC_sendCommand(IPC_CPU1_L_CPU2_R, IPC_FLAG0, IPC_ADDR_CORRECTION_ENABLE,IPC_CMD_READ_MEM, (uint32_t)readData, 10);for(i=0; i<10; i++){j++;readData[i] = i + j*0.5f;}}
}
我是接着我上个文章的代码写的,使用这个主要是为了好测试,若有不懂的代码可以观看我的另一篇博客:TMS320F28388使用sysconfig配置SCI通信(RS485+FIFO+Modbus)
2.2 CPU1的IPC中断代码
__interrupt void IPC_1_ISR(void)
{int i;uint32_t command, addr, data;IPC_readCommand(IPC_CPU1_L_CPU2_R, IPC_FLAG1, IPC_ADDR_CORRECTION_ENABLE,&command, &addr, &data);if(command == IPC_CMD_RESP){float* recvData = (float*)addr;for(i=0; i<data; i++){printf("Float[%d] = %f\r\n", i, recvData[i]);}}IPC_ackFlagRtoL(IPC_CPU1_L_CPU2_R, IPC_FLAG1);Interrupt_clearACKGroup(IPC_1_INTERRUPT_ACK_GROUP);}
2.3 CPU2的主函数IPC代码
第一步:同CPU1的一样,清除IPC标志位,通过IPC_FLAG31同步两个CPU时钟,代码如下
IPC_clearFlagLtoR(IPC_CPU2_L_CPU1_R, IPC_FLAG_ALL);//清除IPC的所有标志位
IPC_sync(IPC_CPU2_L_CPU1_R, IPC_FLAG31);//通过IPC_FLAG31同步两个CPU时钟
第一行解释为:清除CPU1与CPU2通信的IPC的所有FLAG。
第二行解释为:同步CPU时钟代码。
第二步:设置要发送的信息,代码为下:
#pragma DATA_SECTION(Data,"MSGRAM_CPU2_TO_CPU1")
float Data[10];
int i,j;
for(i = 0; i < 10; i++)
{Data[i] = i + j*0.1f; // 与CPU1的内容区分
}
第一行解释为:同CPU1一样,是 TI 编译器的一条 编译指令(pragma 指令),用于将变量 Data
放入指定的内存段 "MSGRAM_CPU2_TO_CPU1"
中,而不是默认的数据段(如 .data
、.bss
)
地址在:
MEMORY
{CPU1TOCPU2RAM : origin = 0x03A000, length = 0x000800CPU2TOCPU1RAM : origin = 0x03B000, length = 0x000800}SECTIONS
{MSGRAM_CPU1_TO_CPU2 : > CPU1TOCPU2RAM, type=NOINITMSGRAM_CPU2_TO_CPU1 : > CPU2TOCPU1RAM, type=NOINIT}
第二行解释位:定义发送数据类型,定义为了一个数组。
第三,四,五行解释为:对数据进行初始化。
第四步:发送数据
while(1)
{DEVICE_DELAY_US(5000000);IPC_sendCommand(IPC_CPU2_L_CPU1_R, IPC_FLAG1, IPC_ADDR_CORRECTION_ENABLE,IPC_CMD_RESP, (uint32_t)Data, 10);for(i = 0; i < 10; i++){Data[i] = i + j*0.1f; // 与CPU1的内容区分}
}
延迟是为了防止数据发送较快,看不出效果,IPC_sendCommand函数中为要发送的数据,数据使用了地址修正功能,
为对数据发送没有影响,可以理解为对数据的功能进行标定,方便对数据进行存储,处理。
CPU2主函数总代码为:
#include "driverlib.h"
#include "device.h"
#include "board.h"
#include "IPC.h"
#include "Interrupt.h"
#include "stdio.h"
int i,j;
#pragma DATA_SECTION(Data, "MSGRAM_CPU2_TO_CPU1")
float Data[10];
void main(void)
{Device_init();//初始化设备时钟和外设Interrupt_initModule();//初始化PIE,清除PIE寄存器,失能CPU中断Interrupt_initVectorTable();//初始化PIE向量表Board_init();//初始化SysConfig配置的外设IPC_clearFlagLtoR(IPC_CPU2_L_CPU1_R, IPC_FLAG_ALL);//清除IPC的所有标志位IPC_sync(IPC_CPU2_L_CPU1_R, IPC_FLAG31);//通过IPC_FLAG31同步两个CPU时钟EINT;//使能所有中断ERTM;//使能允许调试while(1){DEVICE_DELAY_US(5000000);IPC_sendCommand(IPC_CPU2_L_CPU1_R, IPC_FLAG1, IPC_ADDR_CORRECTION_ENABLE,IPC_CMD_RESP, (uint32_t)Data, 10);j++;for(i = 0; i < 10; i++){Data[i] = i + j*0.1f; // 与CPU1的内容区分}}
}
2.4 CPU2的IPC中断代码为
__interrupt void IPC_0_ISR()
{int i;uint32_t command, addr, data;IPC_readCommand(IPC_CPU2_L_CPU1_R, IPC_FLAG0, IPC_ADDR_CORRECTION_ENABLE,&command, &addr, &data);if(command == IPC_CMD_READ_MEM){float* recvData = (float*)addr;for(i=0; i<data; i++){printf("Float[%d] = %f\r\n", i, recvData[i]);}}IPC_ackFlagRtoL(IPC_CPU2_L_CPU1_R, IPC_FLAG0);Interrupt_clearACKGroup(IPC_0_INTERRUPT_ACK_GROUP);
}
第三章 测试结果
CPU1接收到的数据为:
该数据是由CPU2发送的,发送的数据代码为:
for(i = 0; i < 10; i++)
{Data[i] = i + j*0.1f; // 与CPU1的内容区分
}
CPU1接收到的数据符合我们想要发送的数据。通信正常,关于如何使用printf函数,我的上一篇博客有详细的介绍。链接为:TMS320F28388使用sysconfig配置SCI通信(RS485+FIFO+Modbus)
CPU2接收到的数据为:
该数据是由CPU1发送的,发送的数据代码为:
for(i=0; i<10; i++)
{j++;readData[i] = i + j*0.5f;
}
CPU2接收到的数据也符合我们想要发送的数据。通信正常,关于如何使用printf函数打印到控制台,我的上一篇博客也有详细的介绍。链接为:TMS320F28388使用sysconfig配置SCI通信(RS485+FIFO+Modbus)
制作不易,使用请点赞收藏。
相关文章:

TMS320F28388D使用sysconfig配置IPC
第1章 配置IPC底层代码 使用IPC的动机: 我计划我的项目中要使用RS485,CANFD通信和EtherCAT通信,由于通信种类较多,而对于电机控制来说大部分数据都是重复的,并且有些数据可以很久才改变一次,所以我计划使…...
代码训练LeetCode(19)轮转数组
代码训练(19)LeetCode之轮转数组 Author: Once Day Date: 2025年6月3日 漫漫长路,才刚刚开始… 全系列文章可参考专栏: 十年代码训练_Once-Day的博客-CSDN博客 参考文章: 189. 轮转数组 - 力扣(LeetCode)力扣 (LeetCode) 全球极客挚爱的…...
每日算法 -【Swift 算法】将整数转换为罗马数字
💡 Swift:将整数转换为罗马数字(含思路讲解与详细注释) 罗马数字是一种古老的数字表示方式,虽然在现代我们不再使用它进行计算,但在表盘、章节、纪念碑等地方依然很常见。今天我们就来实现一个经典算法题&…...

Qwen与Llama分词器核心差异解析
Qwen和 Llama 词映射(分词器)的区别及通用词映射逻辑 一、Qwen 与 Llama 词映射(分词器)区别 维度Qwen 分词器Llama 分词器技术基础基于字节级别字节对编码(BBPE),以 cl100k 为基础词库,扩充中文字词、多语言词汇基于 BPE,但依赖 SentencePiece 单字模型,核心为英文优…...

华为云Flexus+DeepSeek征文 | 基于ModelArts Studio 与 Cline 快速构建AI编程助手
目录 一、前言 二、ModelArts Studio(MaaS)介绍与应用场景 2.1ModelArts Studio(MaaS)介绍 2.2 ModelArts Studio(MaaS)使用场景 2.3 开通MaaS服务 2.4 开通DeepSeek-V3商用服务 三、Cline简介和安装 3.1 C…...

pikachu靶场通关笔记11 XSS关卡07-XSS之关键字过滤绕过(三种方法渗透)
目录 一、源码分析 1、进入靶场 2、代码审计 3、攻击思路 二、渗透实战 1、探测过滤信息 2、注入Payload1 3、注入Payload2 4、注入Payload3 本系列为通过《pikachu靶场通关笔记》的XSS关卡(共10关)渗透集合,通过对XSS关卡源码的代码审计找到安…...
Android App引用vendor编写的jni动态库
简单描述一下,就是我自己基于FastDDS写了一个Jni的so,然后编写了jar包引用该so,最后写了一个Android的测试apk使用jar包,调用jni中的接口去创建Participant,Subscriber等。 实际将jni的so放到 /system_ext/lib64&#…...
React从基础入门到高级实战:React 核心技术 - 错误处理与错误边界:构建稳定的应用
React 错误处理与错误边界:构建稳定的应用 在开发 React 应用时,错误处理是确保应用稳定性和用户体验的重要环节。无论是运行时错误、API 请求失败还是用户操作失误,合理的错误处理机制都能防止应用崩溃,并为用户提供清晰友好的反…...
页面输入数据的表格字段(如 Web 表单或表格控件)与后台数据库进行交互时常用的两种方式
“从页面输入数据的表格字段(如 Web 表单或表格控件)在与后台数据库进行交互时,常用的有两种方式:” 🎯 两种方式(操作调用数据库、绑定数据) 🚀 方式1:前端代码提交数据到后端,再由后端调用数据库 💡 原理和逻辑: 用户在页面上(比如输入表单、表格)输入数据…...

碰一碰发视频-源码系统开发技术分享
#碰一碰营销系统# #碰一碰系统# #碰一碰发视频# 架构设计哲学:近场通信的优雅平衡 一、核心通信技术选型 1. 双模协同传输引擎 技术协议栈延迟控制适用场景NFCISO 14443-A<100ms精准触发场景BLE 5.0GATT Profile300-500ms中距传输场景 工程决策依据&…...

C++学习过程分享
空指针:int *p NULL; 空指针:指针变量指向内存中编号为0的空间;用途:初始化指针变量注意:空指针指向的内存不允许访问注意:内存编号为0-255为系统占用空间,不允许用户访问 野指针:…...

C语言 — 动态内存管理
目录 1.malloc和free函数1.1 malloc函数1.2 free函数1.3 malloc函数的使用 2.calloc函数2.1 calloc函数2.2 calloc函数的使用 3.realloc函数3.1 realloc函数3.2 realloc函数的使用 4.动态内存管理笔试题4.1 笔试题(1)4.2 笔试题(2)…...

《TCP/IP 详解 卷1:协议》第5章:Internet协议
IPv4和IPv6头部 IP是TCP/IP协议族中的核心协议。所有TCP、UDP、ICMP和IGMP 数据都通过IP数据报传输。IP提供了一种尽力而为、无连接的数据报交付服务。 IP头部字段 IPv4 头部通常为 20 字节(无选项时),而 IPv6 头部固定为 40 字节。IPv6 不…...
C#面向对象实践项目--贪吃蛇
目录 一、项目整体架构与核心逻辑 二、关键类的功能与关系 1. 游戏核心管理类:Game 2. 场景接口与基类 3. 具体场景类 4. 游戏元素类 5. 基础结构体与接口 三.类图 四、核心流程解析 五、项目可优化部分 一、项目整体架构与核心逻辑 该项目运用场景管理模…...

学习STC51单片机26(芯片为STC89C52RCRC)
每日一言 真正的强者,不是没有眼泪,而是含着泪依然奔跑。 硬件:4G模块 这个是接线原理,我们也只要知道这个4根线的连接就好了,我们也是连接到USB转TTL的模块上 要插卡哈......... 随后我们下载一个叫做亿佰特的调试助…...
Web前端为什么要打包?Webpack 和 Vite 如何助力现代开发?
一. 为什么要使用框架库? 1.1 传统网页与现代前端的差异 在最早期的网页开发中,我们只需要写几个.html文件,配上.css和.js文件,浏览器直接加载就能展现页面,每个文件都是独立的静态资源,简单且直观 但现在网站越来越复杂了: 需要用到最新的js语法(比如ES6)使用框架(Vue…...

Nginx详解(三):ngx_http_rewrite_module模块核心指令详解
概要: 在 Nginx 的众多功能模块中,ngx_http_rewrite_module是实现请求动态处理的核心组件,它通过一系列指令实现 URI 重写、条件判断、响应返回等功能。本文将以 CentOS 7.9 环境为例(主机名www.a.com,IP 172.25.0.10…...
C++ 建造者模式:简单易懂的设计模式解析
一、引言 在软件开发中,我们经常会遇到一些复杂对象的创建过程,这些对象通常由多个部分组成,并且每个部分的构建过程可能非常复杂。建造者模式(Builder Pattern)就是为了解决这类问题而诞生的一种创建型设计模式。本文将以简单易懂的方式介绍C++中的建造者模式,帮助你理…...

【笔记】在 MSYS2(MINGW64)中正确安装 Poetry 的指南
#工作记录 在 MSYS2(MINGW64)中正确安装 Poetry 的指南 一、背景说明 在 MSYS2(MINGW64)环境中,即使已经安装了 pip,也不建议直接使用 pip install poetry 来安装 Poetry。 这是因为 MSYS2 使用自己的包…...

IDEA项目推送到远程仓库
打开IDEA——>VCS——>Creat Git 选择项目 push提交到本地 创建远程仓库 复制地址 定义远程仓库 推送 推送成功...
DeepSeek 赋能 NFT:数字艺术创作与交易的革新密码
目录 一、NFT:数字世界的独特资产1.1 NFT 的定义与本质1.2 NFT 的价值支撑1.3 NFT 的丰富类型 二、DeepSeek:AI 领域的创新力量2.1 DeepSeek 的发展历程与成就2.2 DeepSeek 的核心技术与能力 三、DeepSeek 在 NFT 创作中的神奇应用3.1 高效生成数字艺术作…...

【后端架构师的发展路线】
后端架构师的发展路线是从基础开发到技术领导的系统性进阶过程,需融合技术深度、架构思维和业务洞察力。以下是基于行业实践的职业发展路径和关键能力模型: 一、职业发展阶梯 初级工程师(1-3年) 核心能力:掌…...

matlab/simulink TLC语法基础练习实例
一、基本语法测试方法 1.新建一个脚本,保存扩展名为tlc,本例中是tst.tlc,设置当前工作路径为保存的tlc文件路径,在tlc文件里面输入下面的代码,然后保存: %warning test 2.在MATLAB的命令窗口输入: tlc …...
MAU算法流程理解
参考文献:湘江船闸的过闸调度算法研究(李 楠,李桂华,尹剑平) (湖南湘江航运建设开发有限公司,湖南 长沙 410011) MAU算法流程 图4展示的是一种船舶排档算法(MAU算法),它…...

蓝桥杯国赛训练 day1
目录 k倍区间 舞狮 交换瓶子 k倍区间 取模后算组合数就行 import java.util.HashMap; import java.util.Map; import java.util.Scanner;public class Main {static Scanner sc new Scanner(System.in);public static void main(String[] args) {solve();}public static vo…...

ESP32之Linux编译环境搭建流程
背景:为了解决 “windows环境中编译ESP32代码速度慢” 的问题,现搭建一个Linux环境,让windows下的VScode连接到Linux环境,VSCode负责编辑代码,虚拟机用于编译代码。 目录 一、安装VMware 1.1 获取VMware安装包 1.2…...
Linux 软件安装方式全解(适用于 CentOS/RHEL 系统)
🐧 Linux 软件安装方式全解(适用于 CentOS/RHEL 系统) 在 Linux 系统中,软件安装方式丰富多样,常见于以下几种方式: 安装方式命令/工具说明软件包管理器(推荐)yum, dnf, apt, zypp…...
QT- QML Layout+anchors 布局+锚点实现窗口部件权重比例分配
布局管理 简单比较两种界面管理锚点布局实现比例布局布局管理实现比例布局循环依赖问题简谈 在日常打螺丝中,我们偶尔会需要实现界面各组件能按比例放置,自适应各种分辨率的需求。我用锚点和布局都实现过相关界面,记录下来两种方式实现的差异…...

UE5打包项目设置Project Settings(打包widows exe安装包)
UE5打包项目Project Settings Edit-Project Settings- Packaging-Ini Section Denylist-Advanced 1:打包 2:高级设置 3:勾选创建压缩包 4:添加要打包地图Map的数量 5:选择要打包的地图Maps 6:Project-Bui…...
Python中os模块详解
Python os 模块详解 os 模块提供了丰富的文件和目录操作、环境变量访问、进程管理等功能,是与操作系统交互的核心模块之一。 基本导入方式 import os常用目录与文件操作 1️⃣ 获取/设置当前工作目录 os.getcwd() # 获取当前工作目录 os.chdir(/tmp) …...