今回はデルタシグマ型ADC(SDADC)について紹介させて頂きます。
デルタシグマ型ADC(SDADC)は、
一般的な内臓の逐次比較型に比べ、
変換速度は遅いものの、ノイズが少なく、高分解能にAD変換できる特徴があります。
・デルタシグマ型ADC(SDADC)
16bit
16.6 ksps @マルチチャンネル変換
50 ksps @1チャンネル変換
差動信号入力可
・逐次比較型ADC
12bit
最大1Msps
シングル信号のみ
今回はSTM32F373に内臓のSDADCを使用してみました。
HALライブラリで公開されているサンプルは1chのみですが、
2ch読み込みを実験してみました。
環境はSDADC内臓の373シリーズ
・STM32F373CC
+SW4STM32(System Workbench for STM32)
+STM32CubeMX(HAL ライブラリ、F3 ver. 1.60)
です。
◆CubeMXの設定としては、
PB1→SDADC1_AIN5P
PB2→SDADC1_AIN4P
CubeMXで自動生成される初期化関数は下記の通りです。
static void MX_SDADC1_Init(void)
{
SDADC_ConfParamTypeDef ConfParamStruct;
hsdadc1.Instance = SDADC1;
hsdadc1.Init.IdleLowPowerMode = SDADC_LOWPOWER_NONE;
hsdadc1.Init.FastConversionMode = SDADC_FAST_CONV_DISABLE;
hsdadc1.Init.SlowClockMode = SDADC_SLOW_CLOCK_DISABLE;
hsdadc1.Init.ReferenceVoltage = SDADC_VREF_VDDA;
if (HAL_SDADC_Init(&hsdadc1) != HAL_OK)
{
Error_Handler();
}
ConfParamStruct.InputMode = SDADC_INPUT_MODE_SE_ZERO_REFERENCE;
ConfParamStruct.Gain = SDADC_GAIN_1;
ConfParamStruct.CommonMode = SDADC_COMMON_MODE_VSSA;
ConfParamStruct.Offset = 0;
if (HAL_SDADC_PrepareChannelConfig(&hsdadc1,
{
SDADC_ConfParamTypeDef ConfParamStruct;
hsdadc1.Instance = SDADC1;
hsdadc1.Init.IdleLowPowerMode = SDADC_LOWPOWER_NONE;
hsdadc1.Init.FastConversionMode = SDADC_FAST_CONV_DISABLE;
hsdadc1.Init.SlowClockMode = SDADC_SLOW_CLOCK_DISABLE;
hsdadc1.Init.ReferenceVoltage = SDADC_VREF_VDDA;
if (HAL_SDADC_Init(&hsdadc1) != HAL_OK)
{
Error_Handler();
}
ConfParamStruct.InputMode = SDADC_INPUT_MODE_SE_ZERO_REFERENCE;
ConfParamStruct.Gain = SDADC_GAIN_1;
ConfParamStruct.CommonMode = SDADC_COMMON_MODE_VSSA;
ConfParamStruct.Offset = 0;
if (HAL_SDADC_PrepareChannelConfig(&hsdadc1,
SDADC_CONF_INDEX_0,
&ConfParamStruct) != HAL_OK)
{
Error_Handler();
}
if (HAL_SDADC_PrepareChannelConfig(&hsdadc1,
{
Error_Handler();
}
if (HAL_SDADC_PrepareChannelConfig(&hsdadc1,
SDADC_CONF_INDEX_1,
&ConfParamStruct) != HAL_OK)
{
Error_Handler();
}
}
{
Error_Handler();
}
}
◆割り込み関数
追加する割り込み処理として下記の関数を追加します。
void HAL_SDADC_InjectedConvCpltCallback(SDADC_HandleTypeDef *hsdadc)
{
int16_t tmp=HAL_SDADC_InjectedGetValue(hsdadc,
{
int16_t tmp=HAL_SDADC_InjectedGetValue(hsdadc,
(uint32_t *) &Channel);
if(Channel==5)InjectedConvData=tmp; //PB1
else if(Channel==4)InjectedConvData2=tmp; //PB2
}
if(Channel==5)InjectedConvData=tmp; //PB1
else if(Channel==4)InjectedConvData2=tmp; //PB2
}
◆define例として
#define SDADC_RESOL (uint32_t) 65535
#define SDADC_INIT_TIMEOUT 30
#define SDADC_CAL_TIMEOUT 4*30720
#define SDADC_VREF2 (float) 3.300
#define SDADC_GAIN (uint32_t) 1
◆グローバル変数
float inputVoltage = 0;
int16_t ConvData = 0;
uint32_t Channel = 0;
float inputVoltage2 = 0;
int16_t ConvData2 = 0;
uint32_t Channel2 = 1;
mainコード内の例として、
MX_SDADC1_Init();
初期化実行後、詳細設定とキャリブレーション、割り込み開始を実行します。
if (HAL_SDADC_AssociateChannelConfig(&hsdadc1,
SDADC_CHANNEL_4|SDADC_CHANNEL_5,
SDADC_CONF_INDEX_0) != HAL_OK)
{
printf("ERROR: HAL_SDADC_AssociateChannelConfig");
}
if (HAL_SDADC_InjectedConfigChannel(&hsdadc1,
{
printf("ERROR: HAL_SDADC_AssociateChannelConfig");
}
if (HAL_SDADC_InjectedConfigChannel(&hsdadc1,
SDADC_CHANNEL_4|SDADC_CHANNEL_5,
SDADC_CONTINUOUS_CONV_ON) != HAL_OK)
{
printf("ERROR: HAL_SDADC_InjectedConfigChannel");
}
if (HAL_SDADC_SelectInjectedTrigger(&hsdadc1,
{
printf("ERROR: HAL_SDADC_InjectedConfigChannel");
}
if (HAL_SDADC_SelectInjectedTrigger(&hsdadc1,
SDADC_SOFTWARE_TRIGGER) != HAL_OK)
{
printf("ERROR: HAL_SDADC_SelectInjectedTrigger");
}
if (HAL_SDADC_CalibrationStart(&hsdadc1,
{
printf("ERROR: HAL_SDADC_SelectInjectedTrigger");
}
if (HAL_SDADC_CalibrationStart(&hsdadc1,
SDADC_CALIBRATION_SEQ_2) != HAL_OK)
{
printf("ERROR: HAL_SDADC_CalibrationStart");
}
if (HAL_SDADC_PollForCalibEvent(&hsdadc1,
{
printf("ERROR: HAL_SDADC_CalibrationStart");
}
if (HAL_SDADC_PollForCalibEvent(&hsdadc1,
HAL_MAX_DELAY) != HAL_OK)
{
printf("ERROR: HAL_SDADC_PollForCalibEvent");
}
if (HAL_SDADC_InjectedStart_IT(&hsdadc1) != HAL_OK)
{
printf("ERROR: HAL_SDADC_InjectedStart_IT");
}
{
printf("ERROR: HAL_SDADC_PollForCalibEvent");
}
if (HAL_SDADC_InjectedStart_IT(&hsdadc1) != HAL_OK)
{
printf("ERROR: HAL_SDADC_InjectedStart_IT");
}
while関数内では
inputVoltage = (((ConvData + 32768) * SDADC_VREF2)
/ (SDADC_GAIN * SDADC_RESOL));
inputVoltage2 = (((ConvData2 + 32768) * SDADC_VREF2)
inputVoltage2 = (((ConvData2 + 32768) * SDADC_VREF2)
/ (SDADC_GAIN * SDADC_RESOL));
printf("SDADC PB1:%d %1.3f, PB2:%d %1.3f\n\r",
ConvData,
inputVoltage,
ConvData2,
inputVoltage2);
HAL_Delay(300);
HAL_Delay(300);
可変抵抗をつけて実際に読み込んでみました。
確かに値は安定して変化しているようです。
今回は差動入力でなく、シングル入力ですが、
値としては差動として読み込まれるようで、
0V入力で-32768、3.3入力で32768となりました。
温度計など大きく値がぶれない処理によいと思います。