STM32F303K8x ADC Injected Sequencer problemi

Başlatan Cemre., 05 Ekim 2019, 18:57:32

Cemre.

Merhaba,

STM32F303K8x işlemcisinde ADC2 ile Injected Conversation kullanarak 3 kanal ADC dönüşümü yapmak istiyorum. Bu dönüşümü TIM15 TRGO Yükselen Kenar ile tetikleyecek şekilde ayarlıyorum.

Projeyi CubeMX kullanarak Low Layer kütüphaneler üzerinden üretiyorum.

Yaşadığım sorun şu şekilde.
ADC2->JSQR register'ının JSQx bitleri olması gerektiği gibi ayarlanamıyor.
Normal şartlarda JSQ1 = 0x01, JSQ2 = 0x02, JSQ3 = 0x03, JSQ4 = 0x04 şeklinde olması gerekirken
yalnızca JSQ1 = 0x01 diğerleri 0x00 olarak gözüküyor Debug ekranında. Bu nedenle yalnızca Rank1'e ait Channel1 çevrime giriyor. Diğerleri çevrime girmiyor.

Ancak, ben elle Debug ekranından diğer JSQx bitlerini yukarıdaki değerlerle değiştirirsem her şey sorunsuz çalışıyor.

LL kütüphanede bu ayarları yapan fonksiyon LL_ADC_INJ_SetSequencerRanks
Benim ADC ayarlarımda her kanal için ayrı ayrı bu ayar yapılıyor. Ancak yalnızca JSQ1'e karşılık gelen değer doğru bir şekilde yazılırken diğerlerinin hiçbir etkisi olmuyor.

Bunun sebebi ne olabilir?

LL_ADC_INJ_SetSequencerRanks(ADC2, LL_ADC_INJ_RANK_1, LL_ADC_CHANNEL_1);
LL_ADC_INJ_SetSequencerRanks(ADC2, LL_ADC_INJ_RANK_2, LL_ADC_CHANNEL_2);
LL_ADC_INJ_SetSequencerRanks(ADC2, LL_ADC_INJ_RANK_3, LL_ADC_CHANNEL_3);
LL_ADC_INJ_SetSequencerRanks(ADC2, LL_ADC_INJ_RANK_4, LL_ADC_CHANNEL_4);

Cemre.

CubeMX'in ürettiği ADC Init Fonksiyonu

void MX_ADC2_Init(void)
{
  LL_ADC_InitTypeDef ADC_InitStruct = {0};
  LL_ADC_REG_InitTypeDef ADC_REG_InitStruct = {0};
  LL_ADC_INJ_InitTypeDef ADC_INJ_InitStruct = {0};

  LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
  /* Peripheral clock enable */
  LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_ADC12);
  
  LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA);
  /**ADC2 GPIO Configuration  
  PA4   ------> ADC2_IN1
  PA5   ------> ADC2_IN2
  PA6   ------> ADC2_IN3
  PA7   ------> ADC2_IN4 
  */
  GPIO_InitStruct.Pin = iCurrent_U_Pin|iCurrent_V_Pin|iCurrent_W_Pin|iVoltage_Bus_Pin;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
  LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /* ADC2 interrupt Init */
  NVIC_SetPriority(ADC1_2_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
  NVIC_EnableIRQ(ADC1_2_IRQn);

  /** Common config 
  */
  ADC_InitStruct.Resolution = LL_ADC_RESOLUTION_12B;
  ADC_InitStruct.DataAlignment = LL_ADC_DATA_ALIGN_RIGHT;
  ADC_InitStruct.LowPowerMode = LL_ADC_LP_MODE_NONE;
  LL_ADC_Init(ADC2, &ADC_InitStruct);
  ADC_REG_InitStruct.SequencerLength = LL_ADC_REG_SEQ_SCAN_DISABLE;
  ADC_REG_InitStruct.SequencerDiscont = LL_ADC_REG_SEQ_DISCONT_DISABLE;
  ADC_REG_InitStruct.ContinuousMode = LL_ADC_REG_CONV_SINGLE;
  ADC_REG_InitStruct.DMATransfer = LL_ADC_REG_DMA_TRANSFER_LIMITED;
  ADC_REG_InitStruct.Overrun = LL_ADC_REG_OVR_DATA_OVERWRITTEN;
  LL_ADC_REG_Init(ADC2, &ADC_REG_InitStruct);
  LL_ADC_DisableIT_EOC(ADC2);
  LL_ADC_DisableIT_EOS(ADC2);
  LL_ADC_SetCommonClock(__LL_ADC_COMMON_INSTANCE(ADC2), LL_ADC_CLOCK_ASYNC_DIV1);
  /** Configure Injected Channel 
  */
  ADC_INJ_InitStruct.TriggerSource = LL_ADC_INJ_TRIG_EXT_TIM15_TRGO;
  ADC_INJ_InitStruct.SequencerLength = LL_ADC_INJ_SEQ_SCAN_ENABLE_4RANKS;
  ADC_INJ_InitStruct.SequencerDiscont = LL_ADC_INJ_SEQ_DISCONT_DISABLE;
  ADC_INJ_InitStruct.TrigAuto = LL_ADC_INJ_TRIG_INDEPENDENT;
  LL_ADC_INJ_Init(ADC2, &ADC_INJ_InitStruct);
  LL_ADC_INJ_SetQueueMode(ADC2, LL_ADC_INJ_QUEUE_2CONTEXTS_LAST_ACTIVE);
  LL_ADC_DisableIT_JEOC(ADC2);
  LL_ADC_DisableIT_JEOS(ADC2);
  LL_ADC_INJ_SetSequencerRanks(ADC2, LL_ADC_INJ_RANK_1, LL_ADC_CHANNEL_1);
  LL_ADC_SetChannelSamplingTime(ADC2, LL_ADC_CHANNEL_1, LL_ADC_SAMPLINGTIME_1CYCLE_5);
  LL_ADC_SetChannelSingleDiff(ADC2, LL_ADC_CHANNEL_1, LL_ADC_SINGLE_ENDED);
  LL_ADC_INJ_SetTriggerEdge(ADC2, LL_ADC_INJ_TRIG_EXT_RISING);
  /** Configure Injected Channel 
  */
  LL_ADC_INJ_Init(ADC2, &ADC_INJ_InitStruct);
  LL_ADC_INJ_SetQueueMode(ADC2, LL_ADC_INJ_QUEUE_2CONTEXTS_LAST_ACTIVE);
  LL_ADC_DisableIT_JEOC(ADC2);
  LL_ADC_DisableIT_JEOS(ADC2);
  LL_ADC_INJ_SetSequencerRanks(ADC2, LL_ADC_INJ_RANK_2, LL_ADC_CHANNEL_2);
  LL_ADC_SetChannelSamplingTime(ADC2, LL_ADC_CHANNEL_2, LL_ADC_SAMPLINGTIME_1CYCLE_5);
  LL_ADC_SetChannelSingleDiff(ADC2, LL_ADC_CHANNEL_2, LL_ADC_SINGLE_ENDED);
  LL_ADC_INJ_SetTriggerEdge(ADC2, LL_ADC_INJ_TRIG_EXT_RISING);
  /** Configure Injected Channel 
  */
  LL_ADC_INJ_Init(ADC2, &ADC_INJ_InitStruct);
  LL_ADC_INJ_SetQueueMode(ADC2, LL_ADC_INJ_QUEUE_2CONTEXTS_LAST_ACTIVE);
  LL_ADC_DisableIT_JEOC(ADC2);
  LL_ADC_DisableIT_JEOS(ADC2);
  LL_ADC_INJ_SetSequencerRanks(ADC2, LL_ADC_INJ_RANK_3, LL_ADC_CHANNEL_3);
  LL_ADC_SetChannelSamplingTime(ADC2, LL_ADC_CHANNEL_3, LL_ADC_SAMPLINGTIME_1CYCLE_5);
  LL_ADC_SetChannelSingleDiff(ADC2, LL_ADC_CHANNEL_3, LL_ADC_SINGLE_ENDED);
  LL_ADC_INJ_SetTriggerEdge(ADC2, LL_ADC_INJ_TRIG_EXT_RISING);
  /** Configure Injected Channel 
  */
  LL_ADC_INJ_Init(ADC2, &ADC_INJ_InitStruct);
  LL_ADC_INJ_SetQueueMode(ADC2, LL_ADC_INJ_QUEUE_2CONTEXTS_LAST_ACTIVE);
  LL_ADC_DisableIT_JEOC(ADC2);
  LL_ADC_DisableIT_JEOS(ADC2);
  LL_ADC_INJ_SetSequencerRanks(ADC2, LL_ADC_INJ_RANK_4, LL_ADC_CHANNEL_4);
  LL_ADC_SetChannelSamplingTime(ADC2, LL_ADC_CHANNEL_4, LL_ADC_SAMPLINGTIME_1CYCLE_5);
  LL_ADC_SetChannelSingleDiff(ADC2, LL_ADC_CHANNEL_4, LL_ADC_SINGLE_ENDED);
  LL_ADC_INJ_SetTriggerEdge(ADC2, LL_ADC_INJ_TRIG_EXT_RISING);

}

Cemre.

Sorunun kaynağını buldum. Yalnız CubeMX'in bu tuzağa düşmesi, dolayısıyla beni de düşürmesi ilginç.

Sorun Injected Conversion'un Context yapısından kaynaklanıyor. JSQR register'ına her bir Write erişimi bir Context sayılıyor ve bu Context'ler Queue'ya alınıyor. Ancak ADC Init fonksiyonu her bir değişiklik için ayrı ayrı JSQR register'ına eriştiğinden sıradaki ilk değişiklik olan JSQ1 işlevsel olabiliyor. Çünkü en fazla 2 Context olabiliyor (sanırım).

LL_ADC_INJ_SetSequencerRanks fonksiyonu yerine JSQR register'ı üzerinde yapılacak değişiklikleri tek seferde yapmaya yarayan LL_ADC_INJ_ConfigQueueContext fonksiyonu kullanılarak Init işlemi gerçekleştirildiğinde sorun kalmıyor. Ancak bu Context yapısını kullanmıyor olmamdan ötürü bu özelliğin Disable olması gerektiğini düşünmüştüm, bu nedenle üzerine düşmemiştim. CubeMX'in ise bu şekilde bir Init'e izin vermesi ilginç geldi.

Değerli yorumlarınızı bekliyorum.

mufitsozen

Alıntı yapılan: Cemre. - 05 Ekim 2019, 20:03:36Değerli yorumlarınızı bekliyorum.

Benim 2 kurusluk yorumum asagida:

UM1786 icinde JSQR arayarak baslardim ise, ornegin "uint32_t ADC_InjectionConfigTypeDef::ChannelCount
Number of channels in the injected sequence" nasil kullaniliyor onu arastirirdim mesela.


Aptalca bir soru yoktur ve hiç kimse soru sormayı bırakana kadar aptal olmaz.

Cemre.

Ben de bu dokümanı referans alarak çözüme ulaştım.


Ref Manual de bahsediyor, ben ilk bakışta algılayamamıştım.


apsis

#5
.
"Makineye Beyin" MEKATRONİK