[RTD400 LLD]K344 Center Aligned PWM Trigger ADC BCTU

取消
显示结果 
显示  仅  | 搜索替代 
您的意思是: 

[RTD400 LLD]K344 Center Aligned PWM Trigger ADC BCTU

[RTD400 LLD]K344 Center Aligned PWM Trigger ADC BCTU

[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.

 

kerryzhou_12-1737802508258.png

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. 

kerryzhou_13-1737802525461.png

  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.

kerryzhou_14-1737802545570.png

 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. 

kerryzhou_15-1737802657145.png

 Fig 4

So, what are the channels supported by Type G? See the figure below:

kerryzhou_16-1737802660362.png

 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     

kerryzhou_17-1737802664429.png

 Fig 6

Let's take a look at the trigger flag of MCB:

kerryzhou_18-1737802668518.png

 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:

kerryzhou_19-1737802674350.png

 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.

kerryzhou_20-1737802679200.png

 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:

kerryzhou_21-1737802684346.png

 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:

kerryzhou_22-1737802689462.png

 Fig 11 

kerryzhou_23-1737802693578.png

  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:

kerryzhou_24-1737802696994.png

 Fig 13 

kerryzhou_25-1737802702313.png

 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:

kerryzhou_26-1737802711894.png

 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:

kerryzhou_27-1737802722172.png

 Fig 16

(4)Lpuart_Uart

Configure UART6 clock baud rate to 115200. 

kerryzhou_28-1737802726379.png

 Fig 17

(5)Pit 

kerryzhou_29-1737802729584.png

 Fig 18

(6)IntCtrl_Ip

The interrupt configuration is as follows, and it can actually be configured via code.

kerryzhou_30-1737802734820.png

 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:

kerryzhou_31-1737802747820.png

 Fig 20

PWM wave test result is:

Ch1:PTB13 PWM

Ch2:PTA29 BCTU trigger notification

Ch3: PTA2 BCTU watermark notification

kerryzhou_33-1737802767062.png

  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:

kerryzhou_34-1737802770654.png

 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:

kerryzhou_35-1737802774543.png

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

附件
评论

Some customer need the EMIOS0_CH4 falling edge to trigger the BCTU LIST, the modification is:

kerryzhou_1-1739182812746.png

kerryzhou_2-1739182853585.png

kerryzhou_3-1739182873001.png

 

 

kerryzhou_0-1739182779543.png

 

Code is:S32K344_CPWM1k_TRIGMUX_BCTUHWLIST_EMIOSch4_ADC_printf_RTD400.zip

Add another type center trigger method, it is using the EMIOS CH0 MCB counter up as the counter bus, EMIOS0_CH1 as PWM output, EMIOS_CH2 OPWMB, trailing trigger. 

kerryzhou_0-1745500703705.png

 

The test result is:

kerryzhou_0-1745500063009.png

code is: S32K344_NCPWM1k1_TRIGMUX_BCTUHWLIST_EMIOS_ADC_printf_RTD400.zip

 

100% 有帮助 (1/1)
版本历史
最后更新:
‎04-24-2025 06:11 AM
更新人: