【S32M244 RTD200P04 LLD篇8】S32M244 PWM ADC LLD demo
【S32M244 RTD200P04 LLD篇8】S32M244 PWM ADC LLD demo
- 一,文档简介
- 二,PWM+TRGMUX+PDB+ADC 2ch 软件配置与实现
- 2.1 软硬件版本平台
- 2.2 Demo CT 模块配置
- 2.2.1 引脚配置
- 2.2.2 时钟配置
- 2.2.3 外设配置
- 2.3主程序调用情况
- 三, 测试结果
一,文档简介
S32M2XX系列是专门为电机控制而生的MCU系列:
S32M24X,延续S32K14X系列MCU,添加了AE预驱模块。
S32M27X,延续了S32K3系列MCU,添加了AE预驱模块。
NXP官方提供了S32M24X和S32M27X系列的EVB,可以配合一个三相PMSM/BLDC电机,实现单电阻电流采样方式的电机控制。研究电机控制的必经之路是要懂得怎么去控制PWM,实现在特定时刻采集电流,电压信号,并且经过计算再回调PWM控制。本文将基于S32M24X-EVB:
https://www.nxp.com/design/design-center/development-boards-and-designs/S32M24XEVB
讲解如何实现在S32M244上,输出带有死区的互补PWM,并且使用FTM_INT作为触发信号,通过PDB延迟触发ADC采样,将ADC采集的值通过UART打印到PC串口,另外通过TRGMUX模块实现不同模块的相互连接,比如FTM和PDB,还有将信号通过TRGMUX_OUT引脚输出。实现的框图结构如下:
(1)PWM+TRGMUX+PDB+ADC 单通道
配套附件代码:S32M244_FTM_TRGMUX_PDB_ADC_RTD200_P04
(2)PWM+TRGMUX+PDB+ADC 双通道
配套附件代码:S32M244_FTM_TRGMUX_PDB_ADC2ch_RTD200_P04_20k
这里讲解主要基于2通道ADC采样的demo,因为单通道的demo完全可以在2通道的基础上做裁剪,单通道的原则是分享代码。其实本文的主要目的是分享小编自己做的demo,如果熟悉电机控制的,也可以直接参考官方S32M244电机控制demo自行去做。
二,PWM+TRGMUX+PDB+ADC 2ch 软件配置与实现
2.1 软硬件版本平台
硬件:S32M244-EVB
软件:
- S32DS : S32DS.3.5_b220726_win32.x86_64.exe Update 4 for
- S32DS:SW32_S32DS_3.5.4_D2307.zip Development package for S32K1XX:
- SW32K1_S32DS_3.5.4_D2307.zip Development package for S32M2XX:
- SW32M2xx_S32DS_3.5.0_D2303.zip
- RTD:
S32K1_S32M24X Real Time Drivers AUTOSAR 4.4 & R21-11 Version 2.0.0
S32K1_S32M24X Real Time Drivers AUTOSAR R21-11 Version 2.0.0 P04 - S32M24x_AMMCLIB_RTM_1_1_39_BIN
- S32M24XEVB Evaluation Board Motor
- Control Application Software : S32M24XEVB-SW.exe
- FreeMASTER tool 3.2 : FMASTERSW32.exe
这里的软件平台是能够让电机demo都运行起来的这个平台, 如果不需要电机,只需要装S32DS, update,development,RTD即可。
具体的软件链接,建议直接到官网对应软件下载的地方去搜索下载对应版本即可。
2.2 Demo CT 模块配置
首先新建一个S32M244 S32DS 的工程, 然后再去配置引脚,时钟,和外设模块。对于外设主要设计几个模块:Adc_Ip, Ftm_Pwm, Pdb_Adc_Ip, Trgmux_Ip,Lpuart_Uart, Port_Ip
2.2.1 引脚配置
用到的引脚有如下情况:
两个FTM引脚是用于输出带有死区的一对互补PWM。ADC是用来采集板载的可调电位器电压,LPUART用来打印信息, TRGMUX相关引脚是用来输出相关测试信号。
2.2.2 时钟配置
时钟这里需要关注的是:主频时钟,FTM时钟,UART时钟,ADC时钟。
2.2.3 外设配置
使用到的外设情况如下:
(1)Port_Ip_1
讲port的配置,主要是Pcr值的设置原则。
PortPinPcr = PinId + PortId∗32
PortId:A=0,B=1,C=2,D=3,E=4;
PinId就是对应的引脚在port中的号。
上图中,FTM0_CH0是PTC0,则:
PortPinPcr = PinId(0) + PortId(2)∗32=64
(2)Ftm_Pwm模块配置
(3)Adc_Ip模块
(4)Pdb_Adc_Ip
在配置PDB延迟的时候,需要注意,要考虑ADC转换时间,如果一个没转换完,又来一个触发会造成PDB触发时序出错问题。
(5)Trgmux_Ip
这里面包含两部分:FTM连接PDB,还有就是测试信号连接到TRGMUX_OUT输出。
(6)Lpuart_Uart
用于将信号通过printf输出到PC串口终端
2.3主程序调用情况
配置完成之后,可以通过在main中调用如下代码实现PWM触发PDB采集ADC双通道的情况,PWM可以输出互补信号,并且还可以实现相关的触发信号通过TRGMUX_OUT引脚输出:
#include "Mcal.h"
#include "Port_Ci_Port_Ip.h"
#include "Gpio_Dio_Ip.h"
#include "Clock_Ip.h"
#include "Lpuart_Uart_Ip.h"
#include "string.h"
#include "stdio.h"
#include "retarget.h"
#include "Ftm_Pwm_Ip.h"
#include "Ftm_Pwm_Ip_HwAccess.h"
#include "IntCtrl_Ip.h"
#include "Adc_Ip.h"
#include "Pdb_Adc_Ip.h"
#include "Trgmux_Ip.h"
#define PTD1_PORT IP_PTD
#define PTD1_PIN 1U
#define LED_PORT IP_PTE
#define LED_PIN 15U
#define INST_LPUART (0U)
#define INST_FTM0 (0U)
#define WELCOME_MSG_1 "Hello, This message is sent via Uart!\r\n"
volatile Lpuart_Uart_Ip_StatusType lpuartStatus = LPUART_UART_IP_STATUS_ERROR;
uint32 remainingBytes;
uint32 T_timeout = 0xFFFFFF;
uint16 pwmCycleCnt = 0,cntflag = 0,pwmCycleCnt1 = 0, ADCIsrDone = 0;
volatile boolean notif_triggered = FALSE;
volatile uint16 data;
volatile uint16 data2ch[2];
volatile int exit_code = 0;
/* User includes */
void TestDelay(uint32 delay);
void TestDelay(uint32 delay)
{
static volatile uint32 DelayTimer = 0;
while(DelayTimer<delay)
{
DelayTimer++;
}
DelayTimer=0;
}
__attribute__((section (".ramcode")))
void PDB1_SequenceErrorNotif(uint8 ChanIdx, uint16 SeqErrMask)
{
// Read ADCs Results registers to unlock PDB pre-triggers lock states
if (Adc_Ip_GetConvActiveFlag(ADCHWUNIT_0_INSTANCE)){}
Adc_Ip_GetConvData(ADCHWUNIT_0_INSTANCE, 0);
Adc_Ip_GetConvData(ADCHWUNIT_0_INSTANCE, 1);
Ftm_Pwm_Ip_SetInitTriggerCmd(IP_FTM0, true);
/* Unused parameter */
(void)(ChanIdx);
}
__attribute__((section (".ramcode")))
void FTMReloadNotif(void)
{
pwmCycleCnt ++;
}
__attribute__((section (".ramcode")))
void ADC1_ConversionCompleteNotif(const uint8 ControlChanIdx)
{
(void)(ControlChanIdx);
notif_triggered = TRUE;
data2ch[0] = Adc_Ip_GetConvData(ADCHWUNIT_0_INSTANCE, 0);
data2ch[1] = Adc_Ip_GetConvData(ADCHWUNIT_0_INSTANCE, 1);
}
int main(void)
{
Adc_Ip_StatusType adcStatus;
Clock_Ip_Init(&Clock_Ip_aClockConfig[0]);
Port_Ci_Port_Ip_Init(NUM_OF_CONFIGURED_PINS_BOARD_InitPins, g_pin_mux_InitConfigArr_BOARD_InitPins);
IntCtrl_Ip_Init(&IntCtrlConfig_0);
Lpuart_Uart_Ip_Init(INST_LPUART, &Lpuart_Uart_Ip_xHwConfigPB_0);
/**** Part 1: Start ADC software trigger conversions ****/
Adc_Ip_Init(ADCHWUNIT_0_INSTANCE, &AdcHwUnit_0);
adcStatus = Adc_Ip_DoCalibration(ADCHWUNIT_0_INSTANCE);
while (adcStatus != ADC_IP_STATUS_SUCCESS)
{
adcStatus = Adc_Ip_DoCalibration(ADCHWUNIT_0_INSTANCE);
}
#if 1
/* Start a software trigger conversion */
Adc_Ip_StartConversion(ADCHWUNIT_0_INSTANCE, ADC_IP_INPUTCHAN_EXT11, TRUE);
/* Wait for the notification to be triggered and read the data */
while (notif_triggered != TRUE);
notif_triggered = FALSE;
/* Start a software trigger conversion */
Adc_Ip_StartConversion(ADCHWUNIT_0_INSTANCE, ADC_IP_INPUTCHAN_BANDGAP, TRUE);
/* Wait for the notification to be triggered and read the data */
while (notif_triggered != TRUE);
notif_triggered = FALSE;
#endif
if (Adc_Ip_GetConvActiveFlag(ADCHWUNIT_0_INSTANCE)){}
Adc_Ip_GetConvData(ADCHWUNIT_0_INSTANCE, 0);
Adc_Ip_GetConvData(ADCHWUNIT_0_INSTANCE, 1);
/**** Part 2: Start ADC hardware trigger conversions ****/
Adc_Ip_SetTriggerMode(ADCHWUNIT_0_INSTANCE, ADC_IP_TRIGGER_HARDWARE);
Trgmux_Ip_Init(&Trgmux_Ip_xTrgmuxInitPB);
/* Initialize PWM driver */
Ftm_Pwm_Ip_DisableNotification(INST_FTM0, FTM_PWM_IP_OVERFLOW_NOTIFICATION);
Ftm_Pwm_Ip_EnableNotification(INST_FTM0, FTM_PWM_IP_RELOAD_POINT_NOTIFICATION);
Ftm_Pwm_Ip_Init(INST_FTM0, &Ftm_Pwm_Ip_UserCfg0);
Pdb_Adc_Ip_Init(PDBHWUNIT_0_INSTANCE, &PdbHwUnit_0);
Ftm_Pwm_Ip_SetInitTriggerCmd(IP_FTM0, true);
printf("S32M244 FTM TRIGMUX ADC demo RTD200P04.\r\n");
for(;;)
{
printf("pwmCycleCnt = %d \r\n",(int)pwmCycleCnt);
Gpio_Dio_Ip_WritePin(LED_PORT, LED_PIN, 1U);
TestDelay(480000);
Gpio_Dio_Ip_WritePin(LED_PORT, LED_PIN, 0U);
TestDelay(480000);
while (notif_triggered != TRUE);
notif_triggered = FALSE;
printf("adc1_bandGap = %d \r\n",(int)data2ch[0]);
printf("adc1_SE11 = %d \r\n",(int)data2ch[1]);
if((pwmCycleCnt > 30000) && (cntflag==0))
{
cntflag = 1;
Ftm_Pwm_Ip_UpdatePwmDutyCycleChannel(INST_FTM0,0,1000,TRUE);
}
else if((pwmCycleCnt < 30000) && (cntflag==1))
{
cntflag = 0;
Ftm_Pwm_Ip_UpdatePwmDutyCycleChannel(INST_FTM0,0,3000,TRUE);
}
}
return (0U);
}
三, 测试结果
测试结果包括两部分:打印结果看ADC采样值情况,以及PWM输出和PDB触发位置的关系情况。打印结果如下,可以看到ADC的两个通道的值是正确的:
PWM波形测试情况如下:
CH1: PTC0
CH2: PTC1
CH3: PTD0
CH4: PTD1
CH5: PTE11