【RTD400 LLD】K344 センターアライメント PWM トリガー ADC BCTU
【RTD400 LLD】K344 センターアライメント PWM トリガー ADC BCTU
1. アブストラクト
少し前まで、お客様の実際のプロジェクトでは、ADC BCTUマルチチャンネルサンプリングをトリガーするために、中央にアライメントされたPWMの高レベル中心点をS32K3XXに実装する必要がありました。この機能を使用するには、EMIOS、ADC、および BCTU を使用する必要があります。当初、お客様は常にPWMの中心点でトリガーを達成することができず、トリガー位置が間違っていました。その後、K3関連モジュールの原理の説明と分析をお客様に提供した後、実際のコード構成テストのガイダンスを提供し、お客様も必要な機能を達成しました。テストの便宜上、PITおよびUARTのprintf関数もここに追加されています。したがって、ここでは、この関数の特定の状況の要約を示します。これにより、将来同様の機能要件に遭遇する他のお客様が参照を得て、迅速に構築できます。
要件は下図の通りです。アップダウンカウントモードでは、中央揃えのPWMが出力され、ADC BTCU LISTのトリガサンプリングがハイレベルの中心点で実現されます。この記事では、RTD400 LLDバージョンに基づく公式のS32K344-EVBボードでADC BTCU LISTサンプリングを達成するために、1KHZのセンターアライメントPWM、50%デューティサイクル、および高レベルセンターポイントを実装します。
kerryzhou_12-1737802508258.png
図1
2. センターアライメントPWMセンターポイントトリガーADCの原理
原理に関しては、ADCについてサスペンスはありません。ADCソフトウェアとハードウェアのトリガに関する前の記事を直接参照できます。
【RTD400 LLD】K344 ADC SW + HWトリガー
これが図 2 に示す構造です。ADC を設定したら、BCTU でトリガーされた EMIOS チャネルを選択します。EMIOS の関連フラグが生成されると、BCTU がトリガーされます。ウォーターマークに達すると、すべてのLIST ADCチャネル値をバッファに保存するための通知が生成され、ADC値を印刷して簡単に表示することができます view状況に応じて。
kerryzhou_13-1737802525461.png
図2
現在の動作条件では、主に、中央に揃えられたPWMを生成する方法、高レベルの中央ポイントでフラグを生成する方法、およびこのフラグを使用してBTCUサンプリングをトリガーする方法を考慮する必要があります。
2.1 センターアライメントPWMの生成方法
まず、EMIOSのチャネルステータスと、センターアライメントPWMに対応したチャネルステータスについて見ていきましょう。
kerryzhou_14-1737802545570.png
図3
中央揃えのPWMモードはOPWMCBです。
図1に示すように、このモードのカウンタカウントモードはアップとダウンであることがわかります。OPWMCB をサポートするチャネルの種類を見てみましょう。タイプGしかないことがわかります。
kerryzhou_15-1737802657145.png
図4
では、Type Gでサポートされているチャネルは何ですか?次の図を参照してください。
kerryzhou_16-1737802660362.png
図5
謎が解けた。eMIOS の CH1-CH7 のみがセンターアライメント PWM をサポートしています。
さて、そこで新たな疑問が生じます。このモードでは、PWMハイレベルの中心点でトリガー信号を直接生成して、ADC BCTUサンプリングをトリガーできますか?答え:いいえ!
その理由は図1からわかります。このPWMモードでは、アップカウントとダウンカウントの比較が完了したときに生成される2つのトリガフラグがあります。したがって、このモード・チャンネルを使用してADCサンプリングを直接トリガすると、1サイクルで2つのトリガが生成され、どちらもPWMのエッジ上にあります。
OPWMCBはPWMの中心点で直接トリガーを生成できないため、どのように実現しますか?
また、専用のチャンネルを開くと、クロックソースはOPWMCBと同じですが、そのチャンネルはトリガーフラグの生成にカウントされるだけで、波形は出力されません。
2.2 PWM中心点トリガーフラグの生成方法
重要な情報:OPWMCB同時クロックソース、カウントモードのみ、またはアップおよびダウンMCBモード、1つのチャネルのみが満たされます:ADC CH0、カウンターバスタイプもcounter_bus_Bとして選択する必要があります
kerryzhou_17-1737802664429.png
図6
MCB のトリガー フラグを見てみましょう。
kerryzhou_18-1737802668518.png
図7
ご覧の通り、完璧です。トリガーマークは、上向きと下向きのカウントの上部にあり、これは同じソースPWMの高レベルの中心点です。
したがって、ここでは、特定のチャネル配置は原則として決定されており、2つのチャネルがあります:MCBモードEMIOS0_CH0純粋なカウントとフラグの生成をトリガーしてADCサンプリングをトリガーします。EMIOS0_CH1-CH7はOPWMCBモードで、単純に中央揃えのPWMを出力します。
3. ソフトウェアの設定と実装
ソフトウェアはS32K3 RTD400バージョンを使用しており、他のバージョンも同様の構成になっています。
3.1 デモCTモジュールの設定
まず、K344 デモを準備し、次にピン、クロック、およびペリフェラル モジュールを構成する必要があります。以下に、設定について説明します。使用したモジュールは、2つのGPIO、ADC、BCTU、EMIOSクロック、EMIOS PWM、LPUART(ログ印刷用)、PITタイミング印刷用、Trgmuxは設定されていますが、この記事では使用していないので、それについては触れません。
3.1.1ピン構成
使用されるピンは次のとおりです。
kerryzhou_19-1737802674350.png
図8
2つのGPIOは、BCTUトリガ通知とBCTUウォーターマーク通知をそれぞれ切り替えて、波形の位置決めをテストするために使用されます。ADC1にはADC1_s10ピンを使用していますが、この記事では主にBCTUを使用してADC0を組み合わせます。ADC0 は特定の外部ピンを追加せず、内部信号を使用します。LPUARTは印刷に使用され、EMIOS0_CH1はセンターアライメントされたPWM波形を生成するために使用されます。
3.1.2クロック構成
ここで注意が必要なクロックは、ADCクロック、EMIOSクロック、UARTクロック、PITクロックです。
kerryzhou_20-1737802679200.png
図9
これらのクロックは、後で特定のタイミング期間とボーレートを設定するときに使用します。
3.1.3ペリフェラル構成
使用される周辺機器には、主に次のモジュールが含まれます。
kerryzhou_21-1737802684346.png
図10
(1)Adc_Sar_Ip
ADC0モジュールの構成では、1つのトリガーの後に1つの変換を生成するというワンショットモードを使用します。このように、タイマーEMIOSチャネルを使用して、変換をトリガーするトリガー条件を生成できます。プリサンプリングは、前のチャンネルのサンプリング値の残留電荷が電流チャンネルの結果に影響を与え、ADC値の偏差を引き起こすのを防ぐために有効になっています。トリガー モードは BCTU を使用します。ADCプリスケーラ値とキャリブレーションプリスケールの設定では、RMの周波数分割要件を満たす必要があります。最終的な設定は次のとおりです。
kerryzhou_22-1737802689462.png
図11
kerryzhou_23-1737802693578.png
図12
(2)Bctu_Ip
Bctu_Ipの設定では、使用する適切なEMIOSチャネルを選択する必要があります。上記の原則から、EMIOS0_CH0が使用され、次にLISTモードが採用されることがわかります。ADC0 の場合、現在 3 つの内部チャネル (BANDGAP、VREFL、VREFH) がリストに追加されています。具体的な設定は次のとおりです。
kerryzhou_24-1737802696994.png
図13
kerryzhou_25-1737802702313.png
図14
(3)Emios_Mcl_Ip
ここでは、生成する必要のあるPWMサイクルを考慮する必要があります。目標は1Khzの中央に整列したPWMを生成することであるため、EMIOSモードはMCBアップダウンカウントモードです。
MCB のクロック サイクルの式は、(2 x AS1) – 2 です。
では、160MhzのEMIOS0クロックソースの場合、対応する1KHZカウンターは何ですか?最初に160除算を行って1Mhzを取得し、次に(2 x AS1)– 2に従って計算します。
(2 x AS1)– 2 = 1Mhz / 1KHZ = >AS1 = 1000/2 + 1 = 501。
設定は次のとおりです。
kerryzhou_26-1737802711894.png
図15
(3)Emios_Pwm
前の原理分析では、PWMはOPWMCBセンターアライメントモードPWMを使用し、クロックはEMIOS CH0のカウンターバスBから来て、周期は1kHz、デューティサイクルは50%であることを示しています。具体的な設定は次のとおりです。
kerryzhou_27-1737802722172.png
図16
(4)Lpuart_Uart
UART6 クロック ボー レートを 115200 に設定します。
kerryzhou_28-1737802726379.png
図17
(5)ピット
kerryzhou_29-1737802729584.png
図18
(6)IntCtrl_Ip
割り込みの設定は以下の通りで、実際にはコードで設定することができます。
kerryzhou_30-1737802734820.png
図19
3.2 メインコードの状況
コンフィギュレーションが完了したら、メインで次のコードを呼び出すことで、センターPWMの出力とADC BCTUのサンプリングを実現できます。
#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 テスト結果
テスト結果には、印刷された結果がADCのサンプリング値と、PWM出力とBCTUトリガ位置の関係を示す2つの部分があります。印刷された結果は次のとおりで、3つの異なるADCチャネルの値が正しいことがわかります。
kerryzhou_31-1737802747820.png
図20
PWM波テストの結果は次のとおりです。
Ch1:PTB13 PWM
Ch2:PTA29 BCTUトリガー通知
Ch3:PTA2 BCTU透かし通知
kerryzhou_33-1737802767062.png
図21
この図から、最初のBCTUトリガーがPWMハイレベルの中心点にあり、ADCサンプリングが3回トリガーされた後にBCTUウォーターマーク通知がデータを保存するために使用されていることがわかります。
PWMサイクルを表示する別の波形を次に示します。
kerryzhou_34-1737802770654.png
図22
PWM周期は1Khz、デューティサイクルは50%、BCTUの最初のトリガーはPWMハイパルスの中心にあることがわかります。
4.概要と旅行の説明
上記の構成により、最終的にRTD400 LLD方式をS32K344-EVBで使用して、1Khz、50%デューティサイクルのセンターアライメントPWMを実装し、高パルスセンターポジションがADC BCTU LISTの収集をトリガーしました。
遭遇したトリップは、私自身の構成の問題でした。最初は、ウォーターマークの設定値がLISTチャンネルの数と一致していると勘違いしていました。実際、ウォーターマーク トリガーは、ウォーターマーク値を超えた場合にのみトリガーされます。したがって、3チャネルLISTの場合、ウォーターマークは3ではなく2に構成する必要があります。3の場合、テスト波形は次のようになります。
kerryzhou_35-1737802774543.png
図23
ご覧のとおり、ウォーターマーク通知は、実際には4回トリガーされた後に生成されます。
したがって、ウォーターマークのFIFO番号を一致させることを忘れないでください。
愛着:
1. S32K344_centerPWM1k_TRIGMUX_BCTUHWLIST_EMIOS_ADC_printf_RTD400.zip
センターPWMトリガーBCTU LIST
2.S32K344_CPWM1k_TRIGMUX_BCTUHWLIST_EMIOSch4_ADC_printf_RTD400.zip
PWM emios0_ch4立ち下がりエッジは、コメントの状況で BCTU をトリガーします。
3.センタートリガーの別の方法:MCB_Counterアップします。
カウンターバスとしてEmios0_CH0
PWM出力としてのEMIOS0_CH1
EMIOS0_CH2をセンタートリガーとして使用しますが、PWM出力はありません、OPWMB
S32K344_NCPWM1k1_TRIGMUX_BCTUHWLIST_EMIOS_ADC_printf_RTD400.zip
Re: [RTD400 LLD]K344 センターアライメント PWM トリガー ADC BCTU 別のタイプセンタートリガー方法を追加すると、EMIOS CH0 MCBカウンターをカウンターバスとして使用し、EMIOS0_CH1 PWM出力として、OPWMB EMIOS_CH2トレーリングトリガーとして使用します。
kerryzhou_0-1745500703705.png
テスト結果は次のとおりです。
kerryzhou_0-1745500063009.png
code is: S32K344_NCPWM1k1_TRIGMUX_BCTUHWLIST_EMIOS_ADC_printf_RTD400.zip
Re: [RTD400 LLD]K344 センターアライメント PWM トリガー ADC BCTU 一部のお客様は、BCTU LISTをトリガーするためにEMIOS0_CH4下降エッジを必要とし、変更は次のとおりです。
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
查看全文