[RTD400 LLD]K344 Center Aligned PWM Trigger ADC BCTU
1. Abstract
Not long ago, a customer's actual project needed to implement the high-level center point of the center-aligned PWM on the S32K3XX to trigger the ADC BCTU multi-channel sampling. This function requires the use of EMIOS, ADC, and BCTU. At the beginning, the customer was always unable to achieve the trigger at the center point of the PWM, and the trigger position was wrong. Later, After we give the explanation and analysis of the principles of the K3 related modules to the customer, as well as the guidance of the actual code configuration test, and the customer also achieved the required function. For the convenience of testing, PIT and UART printf functions are also added here. So here is a summary of the specific situation of this function, so that other customers who encounter similar functional requirements in the future can have a reference and can quickly build it.
The requirements are as shown in the figure below. In the up-down counting mode, the center-aligned PWM is output, and the trigger sampling of the ADC BTCU LIST is realized at the center point of the high level. This article will implement 1KHZ center-aligned PWM, 50% duty cycle, and high-level center point to achieve ADC BTCU LIST sampling on the official S32K344-EVB board, based on the RTD400 LLD version.
Fig 1
2. Center-aligned PWM center point trigger ADC principle
Regarding the principle, there is no suspense about ADC. You can directly refer to the previous article on ADC software and hardware triggering:
[RTD400 LLD]K344 ADC SW+HW trigger
This is the structure shown in Figure 2. After configuring ADC, BCTU and select the triggered EMIOS channel. When the relevant flag of EMIOS is generated, BCTU will be triggered. After the watermark is reached, a notification will be generated to store all LIST ADC channel values in the buffer, and then the ADC value can be printed out for easy viewing according to the situation.
Fig 2
In the current working condition, the logic that needs to be concerned about is mainly: how to generate center-aligned PWM, how to generate a flag at the high-level center point, and use this flag to trigger BTCU sampling.
2.1 How to generate center-aligned PWM
First, let’s take a look at the channel status of EMIOS and the channel status that supports center-aligned PWM.
Fig 3
The center-aligned PWM mode is: OPWMCB
As shown in Figure 1, we can see that the counter count mode in this mode is up and down. Let's take a look at the channel types that support OPWMCB. We can see that there is only type G.
Fig 4
So, what are the channels supported by Type G? See the figure below:
Fig 5
The mystery is solved. Only CH1-CH7 of eMIOS supports center-aligned PWM.
Well, then a new question arises. Can this mode directly generate a trigger signal at the center point of the PWM high level to trigger the ADC BCTU sampling? Answer: No!
The reason can be seen from Figure 1. In this PWM mode, there are two trigger flags generated when the up and down count comparison is completed. Therefore, if this mode channel is used to directly trigger ADC sampling, two triggers will be generated in one cycle, and both are on the edge of PWM.
Since OPWMCB cannot directly generate a trigger at the center point of PWM, how to achieve it?
In addition, open a dedicated channel, and the clock source is the same as OPWMCB, but that channel only counts to generate trigger flags and does not output any waveform.
2.2 How to generate PWM center point trigger flag
Key information: OPWMCB simultaneous clock source, only counting mode, or up and down MCB mode, only one channel is satisfied: ADC CH0, counter bus type also needs to be selected as counter_bus_B
Fig 6
Let's take a look at the trigger flag of MCB:
Fig 7
As you can see, it is perfect. The trigger mark is at the top of the upward and downward counting, which is exactly the center point of the high level of the same source PWM.
So, here, the specific channel arrangement has been determined in principle, two channels: EMIOS0_CH0 MCB mode pure counting and triggering the generation of flags to trigger ADC sampling; EMIOS0_CH1-CH7 is OPWMCB mode, simply outputting center-aligned PWM.
3. Software configuration and implementation
The software uses the S32K3 RTD400 version, and other versions have similar configurations!
3.1 Demo CT module configuration
First, you need to prepare a K344 demo, and then configure the pins, clocks, and peripheral modules. The following will explain the configurations. The modules used are: 2 GPIOs, ADC, BCTU, EMIOS clock, EMIOS PWM, LPUART for printing logs, PIT for timed printing, Trgmux is configured but not used in this article, so I won't talk about it!
3.1.1 Pin configuation
The pins used are as follows:
Fig 8
The two GPIOs are used to toggle in BCTU trigger notification and BCTU watermark notification respectively, to test the waveform positioning. ADC1_s10 pin is used for ADC1, but this article mainly uses BCTU to combine ADC0. ADC0 does not add specific external pins, but uses internal signals. LPUART is used for printing, and EMIOS0_CH1 is used to generate center-aligned PWM waveforms.
3.1.2 Clock configuration
The clocks that need to be paid attention to here are: ADC clock, EMIOS clock, UART clock, and PIT clock.
Fig 9
These clocks will be used later when configuring specific timing periods and baud rates.
3.1.3 Peripheral configuration
The peripherals used mainly include the following modules:
Fig 10
(1)Adc_Sar_Ip
The configuration of the ADC0 module uses the one shot mode, that is, one conversion is generated after one trigger. In this way, the timer EMIOS channel can be used to generate trigger conditions to trigger a conversion. Pre-sampling is enabled to prevent the residual charge of the sampled value of the previous channel from affecting the result of the current channel and causing deviation of the ADC value. The trigger mode uses BCTU. For the configuration of Adc prescaler value and calibration prescale, the frequency division requirements in RM need to be met. The final configuration is as follows:
Fig 11
Fig 12
(2)Bctu_Ip
The configuration of Bctu_Ip needs to select the right EMIOS channel to use. From the above principle, we can know that EMIOS0_CH0 is used, and then LIST mode is adopted. For ADC0, three internal channels are currently added to the LIST: BANDGAP, VREFL, VREFH. The specific configuration is as follows:
Fig 13
Fig 14
(3)Emios_Mcl_Ip
Here we need to consider the PWM cycle that needs to be generated. The goal is to generate a 1Khz center-aligned PWM, so the EMIOS mode is the MCB up-down counting mode.
The clock cycle formula for MCB is: (2 x AS1) – 2.
So for the EMIOS0 clock source of 160Mhz, what is the corresponding 1KHZ counter? First do 160 divide to get 1Mhz, and then calculate according to (2 x AS1) – 2:
(2 x AS1) – 2 = 1Mhz/1KHZ=>AS1=1000/2 +1= 501.
The configuration is as follows:
Fig 15
(3)Emios_Pwm
The previous principle analysis shows that the PWM uses the OPWMCB center-aligned mode PWM, the clock comes from the counter bus B of EMIOS CH0, then the period is 1khz, and the duty cycle is 50%. The specific configuration is as follows:
Fig 16
(4)Lpuart_Uart
Configure UART6 clock baud rate to 115200.
Fig 17
(5)Pit
Fig 18
(6)IntCtrl_Ip
The interrupt configuration is as follows, and it can actually be configured via code.
Fig 19
3.2 Main code situation
After the configuration is completed, the output of the center PWM and the sampling of the ADC BCTU can be realized by calling the following code in main.
#include "Clock_Ip.h"
#include "IntCtrl_Ip.h"
#include "Adc_Sar_Ip.h"
#include "Bctu_Ip.h"
#include "Siul2_Port_Ip.h"
#include "Pit_Ip.h"
#include "Siul2_Dio_Ip.h"
#include "Trgmux_Ip.h"
#include "Lpuart_Uart_Ip.h"
#include "Lpuart_Uart_Ip_Irq.h"
#include "string.h"
#include "stdio.h"
#include "retarget.h"
#include "Emios_Mcl_Ip.h"
#include "Emios_Pwm_Ip.h"
/* PIT instance used - 0 */
#define PIT_INST_0 0U
/* PIT Channel used - 0 */
#define CH_0 0U
/* PIT time-out period - equivalent to 1s */
#define PIT_PERIOD 40000000
static volatile uint8 toggleLed = 0U;
#ifdef ADC_3V3_VREF_SELECTED
#define ADC_BANDGAP 5980U /* Vbandgap ~ 1.2V on 14 bits resolution, 3.3V VrefH */
#else
#define ADC_BANDGAP 3932U /* Vbandgap ~ 1.2V on 14 bits resolution, 5V VrefH */
#endif
#define ADC_SAR_USED_CH 48U /* Internal Bandgap Channel */
#define BCTU_USED_SINGLE_TRIG_IDX 0U
#define BCTU_USED_FIFO_IDX 0U
#define BCTU_FIFO_WATERMARK 3U
#define ADC_TOLERANCE(x,y) (((x > y) ? (x - y) : (y - x)) > 200U) /* Check that the data is within tolerated range */
#define LED_Q172_PIN 13u
#define LED_Q172_PORT PTA_H_HALF
#define GPIO_PTA2_PIN 2u
#define GPIO_PTA2_PORT PTA_L_HALF
#define EMIOS_INST0 0U
volatile int exit_code = 0;
volatile boolean notif_triggered = FALSE;
volatile boolean notif_triggered1 = FALSE;
volatile uint16 data;
volatile uint16 data1;
volatile uint16 data_bctu[3];
#define UART_LPUART_INTERNAL_CHANNEL 6
#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;
uint8* pBuffer;
extern void Adc_Sar_0_Isr(void);
extern void Bctu_0_Isr(void);
extern void Adc_Sar_1_Isr(void);
void AdcEndOfChainNotif(void)
{
notif_triggered = TRUE;
data = Adc_Sar_Ip_GetConvData(ADCHWUNIT_0_BOARD_INITPERIPHERALS_INSTANCE, ADC_SAR_USED_CH);
/* Checks the measured ADC data conversion */
}
void AdcEndOfChainNotif1(void)
{
notif_triggered1 = TRUE;
data1 = Adc_Sar_Ip_GetConvData(ADCHWUNIT_1_BOARD_INITPERIPHERALS_INSTANCE, 34);
/* Checks the measured ADC data conversion */
}
void Pit0ch0Notification(void)
{
toggleLed = 1U;
}
void BctuWatermarkNotif(void)
{
uint8 idx;
Siul2_Dio_Ip_WritePin(GPIO_PTA2_PORT, GPIO_PTA2_PIN, 1U);
notif_triggered = TRUE;
for (idx = 0u; idx < BCTU_FIFO_WATERMARK; idx++)
{
data_bctu[idx] = Bctu_Ip_GetFifoData(BCTUHWUNIT_0_BOARD_INITPERIPHERALS_INSTANCE, BCTU_USED_FIFO_IDX);
}
Siul2_Dio_Ip_WritePin(GPIO_PTA2_PORT, GPIO_PTA2_PIN, 0U);
}
void BcutTriggerNotif()
{
Siul2_Dio_Ip_WritePin(LED_Q172_PORT, LED_Q172_PIN, 1U);
Siul2_Dio_Ip_WritePin(LED_Q172_PORT, LED_Q172_PIN, 0U);
}
void TestDelay(uint32 delay);
void TestDelay(uint32 delay)
{
static volatile uint32 DelayTimer = 0;
while(DelayTimer < delay)
{
DelayTimer++;
}
DelayTimer = 0;
}
int main(void)
{
StatusType status;
uint8 Index;
Clock_Ip_StatusType clockStatus;
/* Initialize and configure drivers */
clockStatus = Clock_Ip_Init(&Clock_Ip_aClockConfig[0]);
while (clockStatus != CLOCK_IP_SUCCESS)
{
clockStatus = Clock_Ip_Init(&Clock_Ip_aClockConfig[0]);
}
Siul2_Port_Ip_Init(NUM_OF_CONFIGURED_PINS_PortContainer_0_BOARD_InitPeripherals, g_pin_mux_InitConfigArr_PortContainer_0_BOARD_InitPeripherals);
#if 1
Bctu_Ip_Init(BCTUHWUNIT_0_BOARD_INITPERIPHERALS_INSTANCE, &BctuHwUnit_0_BOARD_INITPERIPHERALS);
status = (StatusType) Adc_Sar_Ip_Init(ADCHWUNIT_0_BOARD_INITPERIPHERALS_INSTANCE, &AdcHwUnit_0_BOARD_InitPeripherals);
while (status != E_OK);
status = (StatusType) Adc_Sar_Ip_Init(ADCHWUNIT_1_BOARD_INITPERIPHERALS_INSTANCE, &AdcHwUnit_1_BOARD_InitPeripherals);
while (status != E_OK);
/* set PIT 0 interrupt */
IntCtrl_Ip_Init(&IntCtrlConfig_0);
IntCtrl_Ip_EnableIrq(PIT0_IRQn);
/* Install and enable interrupt handlers */
IntCtrl_Ip_InstallHandler(ADC0_IRQn, Adc_Sar_0_Isr, NULL_PTR);
IntCtrl_Ip_InstallHandler(BCTU_IRQn, Bctu_0_Isr, NULL_PTR);
IntCtrl_Ip_InstallHandler(ADC1_IRQn, Adc_Sar_1_Isr, NULL_PTR);
IntCtrl_Ip_EnableIrq(ADC0_IRQn);
IntCtrl_Ip_EnableIrq(BCTU_IRQn);
IntCtrl_Ip_EnableIrq(ADC1_IRQn);
// IntCtrl_Ip_EnableIrq(EMIOS0_5_IRQn);
/* Call Calibration function multiple times, to mitigate instability of board source */
for(Index = 0; Index <= 5; Index++)
{
status = (StatusType) Adc_Sar_Ip_DoCalibration(ADCHWUNIT_0_BOARD_INITPERIPHERALS_INSTANCE);
if(status == E_OK)
{
break;
}
}
for(Index = 0; Index <= 5; Index++)
{
status = (StatusType) Adc_Sar_Ip_DoCalibration(ADCHWUNIT_1_BOARD_INITPERIPHERALS_INSTANCE);
if(status == E_OK)
{
break;
}
}
Adc_Sar_Ip_EnableNotifications(ADCHWUNIT_0_BOARD_INITPERIPHERALS_INSTANCE, ADC_SAR_IP_NOTIF_FLAG_NORMAL_ENDCHAIN | ADC_SAR_IP_NOTIF_FLAG_INJECTED_ENDCHAIN);
Adc_Sar_Ip_EnableNotifications(ADCHWUNIT_1_BOARD_INITPERIPHERALS_INSTANCE, ADC_SAR_IP_NOTIF_FLAG_NORMAL_ENDCHAIN | ADC_SAR_IP_NOTIF_FLAG_INJECTED_ENDCHAIN);
/* Start a SW triggered normal conversion on ADC_SAR */
Adc_Sar_Ip_StartConversion(ADCHWUNIT_0_BOARD_INITPERIPHERALS_INSTANCE, ADC_SAR_IP_CONV_CHAIN_NORMAL);
/* Wait for the notification to be triggered and read the data */
while (notif_triggered != TRUE);
notif_triggered = FALSE;
/* Start a SW triggered injected conversion on ADC_SAR */
Adc_Sar_Ip_StartConversion(ADCHWUNIT_0_BOARD_INITPERIPHERALS_INSTANCE, ADC_SAR_IP_CONV_CHAIN_INJECTED);
/* Wait for the notification to be triggered and read the data */
while (notif_triggered != TRUE);
notif_triggered = FALSE;
#endif
/* Initialize PIT instance 0 - Channel 0 */
Pit_Ip_Init(PIT_INST_0, &PIT_0_InitConfig_PB_BOARD_InitPeripherals);
/* Initialize channel 0 */
Pit_Ip_InitChannel(PIT_INST_0, PIT_0_CH_0);
/* Enable channel interrupt PIT_0 - CH_0 */
Pit_Ip_EnableChannelInterrupt(PIT_INST_0, CH_0);
/* Start channel CH_0 */
Pit_Ip_StartChannel(PIT_INST_0, CH_0, PIT_PERIOD);
// Trgmux_Ip_Init(&Trgmux_Ip_xTrgmuxInitPB);//
Lpuart_Uart_Ip_Init(UART_LPUART_INTERNAL_CHANNEL, &Lpuart_Uart_Ip_xHwConfigPB_6_BOARD_INITPERIPHERALS);
Emios_Mcl_Ip_Init(EMIOS_INST0, &Emios_Mcl_Ip_0_Config_BOARD_INITPERIPHERALS);
Emios_Pwm_Ip_InitChannel(EMIOS_PWM_IP_BOARD_INITPERIPHERALS_I0_CH1_CFG, &Emios_Pwm_Ip_BOARD_InitPeripherals_I0_Ch1);
printf("S32K344 PIT TRIGMUX ADC demo RTD400.\r\n");
/* Uart_AsyncSend transmit data */
lpuartStatus = Lpuart_Uart_Ip_AsyncSend(UART_LPUART_INTERNAL_CHANNEL, (const uint8 *) WELCOME_MSG_1, strlen(WELCOME_MSG_1));
/* Check for no on-going transmission */
do
{
lpuartStatus = Lpuart_Uart_Ip_GetTransmitStatus(UART_LPUART_INTERNAL_CHANNEL, &remainingBytes);
} while (LPUART_UART_IP_STATUS_BUSY == lpuartStatus && 0 < T_timeout--);
Siul2_Dio_Ip_WritePin(GPIO_PTA2_PORT, GPIO_PTA2_PIN, 0U);
while(1)
{
#if 1
if( toggleLed == 1)
{
toggleLed = 0;
printf("ADC0_bandgap ch48 data_bctu = %d .\r\n", data_bctu[0]);
printf("ADC0_vrefl ch54 data_bctu = %d .\r\n", data_bctu[1]);
printf("ADC0_vrefh ch55 data_bctu = %d .\r\n", data_bctu[2]);
}
#endif
}
return exit_code;
}
3.3 Test result
The test results include two parts: the printed results show the ADC sampling value, and the relationship between the PWM output and the BCTU trigger position. The printed results are as follows, and you can see that the values of the three different ADC channels are correct:
Fig 20
PWM wave test result is:
Ch1:PTB13 PWM
Ch2:PTA29 BCTU trigger notification
Ch3: PTA2 BCTU watermark notification
Fig 21
From the figure, we can see that the first BCTU trigger is at the center point of the PWM high level, and the BCTU watermark notification is used to store data after the ADC sampling is triggered three times.
Here is another waveform to view the PWM cycle:
Fig 22
It can be seen that the PWM period is 1Khz, the duty cycle is 50%, and the first trigger of BCTU is at the center of the PWM high pulse.
4. Summary and trip description
Through the above configuration, the RTD400 LLD method was finally used on the S32K344-EVB to implement a 1Khz, 50% duty cycle center-aligned PWM, and the high pulse center position triggered the ADC BCTU LIST acquisition.
The trip encountered were my own configuration problems. At the beginning, I mistakenly thought that the watermark configuration value was consistent with the number of LIST channels. In fact, the watermark trigger is triggered only when the watermark value is exceeded. Therefore, if it is a 3-channel LIST, the watermark needs to be configured as 2, not 3. If it is 3, the test waveform is as follows:
Fig 23
As you can see, the watermark notification is actually generated after it is triggered 4 times.
Therefore, remember to match the FIFO number of the watermark.
Attachment:
1. S32K344_centerPWM1k_TRIGMUX_BCTUHWLIST_EMIOS_ADC_printf_RTD400.zip
Center PWM triggered BCTU LIST
2.S32K344_CPWM1k_TRIGMUX_BCTUHWLIST_EMIOSch4_ADC_printf_RTD400.zip
PWM emios0_ch4 falling edge trigger the BCTU, for the comment situation.
3. Another method of center trigger: MCB_Counter up.
Emios0_CH0 as the counter bus
EMIOS0_CH1 as the PWM output
EMIOS0_CH2 as the center trigger, but no PWM output, OPWMB
S32K344_NCPWM1k1_TRIGMUX_BCTUHWLIST_EMIOS_ADC_printf_RTD400.zip
記事全体を表示