Någon som förstår det där med DMA i STM32?

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
DanielM
Inlägg: 2166
Blev medlem: 5 september 2019, 14:19:58

Någon som förstår det där med DMA i STM32?

Inlägg av DanielM »

Jag har bråkat med ett litet problem allt för länge nu. Det är DMA, något som jag har använt mig mycket utav, men av någon lustig anledning så verkar det vara olika konfigurationer av DMA beroende på vilket periferi man använder hos mikrokontrollern.

Jag använder DMA till Input Capute(IC) och DMA till Sigma Delta ADC (SDADC) som har hela 16-bit upplösning, vilket är riktigt bra.
Normalt sett så använde jag interrupt på IC och SDADC, vilket fungerade bra vid låg användning. Men så fort signalerna började pulsera och analoga ingångarna fick förändrat värde, så tog interrupt upp all CPU-tid. Så därför använder jag DMA.

SDADC:
När jag konfiguerade min SDADC så valde jag att använda "Injected Conversion", istället för "Regular Conversion". Skilllnaden är att med "Injected Conversion" så får man bestämma lite mera och koppla SDADC mot en timer, vilket jag tycker är bättre istället för att låta "Regular Conversion", vilket är att processorn själv bestämmer när SDADC ska börja samlpa. Man vet aldrig, det kanske händer. Något som har inträffat mig med "Injected Conversion".
Så här ser det ut för alla SDADC:er. Jag har totalt tre stycken.
  • SDADC1 har Timer 13 Compare Output 1 samt DMA2 kanal 3
  • SDADC2 har Timer 12 Compare Output 1 samt DMA2 kanal 4
  • SDADC3 har Timer 12 Compare Output 2 samt DMA2 kanal 5
Skärmklipp.PNG
Skärmklipp.PNG
Först så vill jag bara säga att detta fungerar utmärkt om jag använder Interrupt. Men använder jag DMA så fungerar det icke!
När jag startar upp mina SDADC:er så använder jag denna C-kod.

Kod: Markera allt

volatile static int16_t SDADC1_Single[9];
volatile static int16_t SDADC2_Single[3];
volatile static int16_t SDADC3_Differential[5];
static float SDADC_Single_Calibration_Gain[12] = {0};
static float SDADC_Single_Calibration_Bias[12] = {0};
static float SDADC_Differential_Calibration_Gain[5] = {0};
static float SDADC_Differential_Calibration_Bias[5] = {0};
TIM_HandleTypeDef *handler_tim12;
TIM_HandleTypeDef *handler_tim13;
SDADC_HandleTypeDef *handler_sdadc1;
SDADC_HandleTypeDef *handler_sdadc2;
SDADC_HandleTypeDef *handler_sdadc3;

void STM32_PLC_Start_Analog_Input(TIM_HandleTypeDef* htim12, TIM_HandleTypeDef* htim13, SDADC_HandleTypeDef* hsdadc1, SDADC_HandleTypeDef* hsdadc2, SDADC_HandleTypeDef* hsdadc3) {
	/*
	 * For TIM12, TIM13 and TIM16
	 * Timer clock: 48 Mhz
	 * Prescaler: 0
	 * Counter: 48000 (0xbb80)
	 * Update frequency: 1000 Hz
	 */
	HAL_TIM_OC_Start(htim13, TIM_CHANNEL_1); /* TIM13 Channel 1 is trigger source for SDADC1 */
	HAL_TIM_OC_Start(htim12, TIM_CHANNEL_1); /* TIM12 Channel 1 is trigger source for SDADC2 */
	HAL_TIM_OC_Start(htim12, TIM_CHANNEL_2); /* TIM12 Channel 2 is trigger source for SDADC3 */
	if (HAL_SDADC_CalibrationStart(hsdadc1, SDADC_CALIBRATION_SEQ_1) != HAL_OK)
		Error_Handler();
	if (HAL_SDADC_CalibrationStart(hsdadc2, SDADC_CALIBRATION_SEQ_1) != HAL_OK)
		Error_Handler();
	if (HAL_SDADC_CalibrationStart(hsdadc3, SDADC_CALIBRATION_SEQ_1) != HAL_OK)
		Error_Handler();
	if (HAL_SDADC_PollForCalibEvent(hsdadc1, HAL_MAX_DELAY) != HAL_OK)
		Error_Handler();
	if (HAL_SDADC_PollForCalibEvent(hsdadc2, HAL_MAX_DELAY) != HAL_OK)
		Error_Handler();
	if (HAL_SDADC_PollForCalibEvent(hsdadc3, HAL_MAX_DELAY) != HAL_OK)
		Error_Handler();
	if(HAL_SDADC_InjectedStart_DMA(hsdadc1, (uint32_t*)SDADC1_Single, 9) != HAL_OK)
		Error_Handler();
	if(HAL_SDADC_InjectedStart_DMA(hsdadc2, (uint32_t*)SDADC2_Single, 3) != HAL_OK)
		Error_Handler();
	if(HAL_SDADC_InjectedStart_DMA(hsdadc3, (uint32_t*)SDADC3_Differential, 5) != HAL_OK)
		Error_Handler();

	/* Save */
	handler_tim13 = htim13;
	handler_tim12 = htim12;
	handler_sdadc1 = hsdadc1;
	handler_sdadc2 = hsdadc2;
	handler_sdadc3 = hsdadc3;

}
Detta resulterar att arrayerna nedan är alltid 0. Dom har alltid 0 värden i sina element.

Kod: Markera allt

volatile static int16_t SDADC1_Single[9];
volatile static int16_t SDADC2_Single[3];
volatile static int16_t SDADC3_Differential[5];
Dessutom när jag vill andra förstärkning och förskjutning på min SDADC så anropar jag denna kod. Koden börjar med att initialisera en struktur för att sätta funktion på SDADC:n. Variabeln sdadc har 3 olika värde: 1, 2, 3 och dessa bestämmer vilken SDADC jag vill förändra. Jag börjar alltid med att stoppa DMA, men här styper jag.

Kod: Markera allt

/* Inline is only for optimization */
static inline int16_t* array_to_pointer(int16_t array[]){
	return array; /* This return the address */
}

void STM32_PLC_Analog_Input_Set_Gain_Offset(uint8_t sdadc, uint8_t configuration_index, uint8_t gain, uint16_t offset) {
	/* Initial */
	SDADC_ConfParamTypeDef ConfParamStruct = {0};
	ConfParamStruct.CommonMode = SDADC_COMMON_MODE_VSSA;
	SDADC_HandleTypeDef *handler;
	uint8_t length_DMA;
	uint32_t *array_DMA;

	/* Stop DMA */
	switch(sdadc){
	case 1:
		/* Stop DMA for SDADC1 */
		if(HAL_SDADC_InjectedStop_DMA(handler_sdadc1) != HAL_OK)
			Error_Handler();
		handler = handler_sdadc1;
		length_DMA = 9;
		array_DMA = (uint32_t*)array_to_pointer((int16_t*)SDADC1_Single);
		ConfParamStruct.InputMode = SDADC_INPUT_MODE_SE_ZERO_REFERENCE;
		break;
	case 2:
		/* Stop DMA for SDADC2 */
		if(HAL_TIM_OC_Stop(handler_tim12, TIM_CHANNEL_1))
			Error_Handler();
		if(HAL_SDADC_InjectedStop_DMA(handler_sdadc2) != HAL_OK)
			Error_Handler();
		handler = handler_sdadc2;
		length_DMA = 3;
		array_DMA = (uint32_t*)array_to_pointer((int16_t*)SDADC2_Single);
		ConfParamStruct.InputMode = SDADC_INPUT_MODE_SE_ZERO_REFERENCE;
		break;
	case 3:
		/* Stop DMA for SDADC3 */
		if(HAL_SDADC_InjectedStop_DMA(handler_sdadc3) != HAL_OK)
			Error_Handler();
		handler = handler_sdadc3;
		length_DMA = 5;
		array_DMA = (uint32_t*)array_to_pointer((int16_t*)SDADC3_Differential);
		ConfParamStruct.InputMode = SDADC_INPUT_MODE_DIFF;
		break;
	default:
		/* Stop DMA for SDADC1 */
		if(HAL_SDADC_InjectedStop_DMA(handler_sdadc1) != HAL_OK)
			Error_Handler();
		handler = handler_sdadc1;
		length_DMA = 9;
		array_DMA = (uint32_t*)array_to_pointer((int16_t*)SDADC1_Single);
		ConfParamStruct.InputMode = SDADC_INPUT_MODE_SE_ZERO_REFERENCE;
		break;
	}

	/* Set gain and offset */
	switch(gain){
	case 0:
		ConfParamStruct.Gain = SDADC_GAIN_1_2;
		break;
	case 1:
		ConfParamStruct.Gain = SDADC_GAIN_1;
		break;
	case 2:
		ConfParamStruct.Gain = SDADC_GAIN_2;
		break;
	case 3:
		ConfParamStruct.Gain = SDADC_GAIN_4;
		break;
	case 4:
		ConfParamStruct.Gain = SDADC_GAIN_8;
		break;
	case 5:
		ConfParamStruct.Gain = SDADC_GAIN_16;
		break;
	case 6:
		ConfParamStruct.Gain = SDADC_GAIN_32;
		break;
	default:
		ConfParamStruct.Gain = SDADC_GAIN_1;
		offset = 0;
		break;
	}
	ConfParamStruct.Offset = offset;

	/* Set calibration */
	if (HAL_SDADC_PrepareChannelConfig(handler, configuration_index, &ConfParamStruct) != HAL_OK)
	    Error_Handler();

	/* Start ADC again */
	if (HAL_SDADC_CalibrationStart(handler, SDADC_CALIBRATION_SEQ_1) != HAL_OK)
		Error_Handler();
	if (HAL_SDADC_PollForCalibEvent(handler, HAL_MAX_DELAY) != HAL_OK)
		Error_Handler();
	if(HAL_SDADC_InjectedStart_DMA(handler, array_DMA, length_DMA) != HAL_OK)
		Error_Handler();
}
Så fort jag försöker stoppa DMA så går jag in i funktionen.

Kod: Markera allt

HAL_StatusTypeDef HAL_SDADC_InjectedStop_DMA(SDADC_HandleTypeDef *hsdadc)
{
  HAL_StatusTypeDef status;

  /* Check parameters */
  assert_param(IS_SDADC_ALL_INSTANCE(hsdadc->Instance));

  /* Check SDADC state */
  if((hsdadc->State != HAL_SDADC_STATE_INJ) && \
     (hsdadc->State != HAL_SDADC_STATE_REG_INJ))
  {
    /* Return error status */
    status = HAL_ERROR;
  }
  else
  {
    /* Clear JDMAEN bit in SDADC_CR1 register */
    hsdadc->Instance->CR1 &= ~(SDADC_CR1_JDMAEN);

    /* Stop current DMA transfer */
    if(HAL_DMA_Abort(hsdadc->hdma) != HAL_OK)
    {
      /* Set SDADC in error state */
      hsdadc->State = HAL_SDADC_STATE_ERROR;
      status = HAL_ERROR;
    }
Där efter går jag in i "HAL_DMA_Abort" funktionen. Här styper jag för att hdma->State är lika med HAL_DMA_STATE_READY. Alltså betyder det att DMA var inte aktiverad redan från början? Eller vad tror ni?

Kod: Markera allt

HAL_StatusTypeDef HAL_DMA_Abort(DMA_HandleTypeDef *hdma)
{
  if(hdma->State != HAL_DMA_STATE_BUSY)
  {
    /* no transfer ongoing */
    hdma->ErrorCode = HAL_DMA_ERROR_NO_XFER;
    
    /* Process Unlocked */
    __HAL_UNLOCK(hdma);
    
    return HAL_ERROR;
  }
IC:
Ett annat problem är detta. Jag får bara IC för htim17 att fungera. Medan htim16 verkar bara köras en gång.

Kod: Markera allt

volatile static uint16_t input_capture0[2] = {0};
volatile static uint16_t input_capture1[2] = {0};

void STM32_PLC_Start_Input_Capture(TIM_HandleTypeDef* htim17, TIM_HandleTypeDef* htim16) {
	/*
	 * Input capture for measuring frequency
	 * For TIM17 and TIM16
	 * Timer clock: 48 Mhz
	 * Prescaler: 4799
	 * Counter: 65535 (0xffff)
	 * Update frequency: 0.1526 Hz (1/0.1526 = 6.5535 seconds)
	 * Example: For every second, it will count 10000
	 * Lowest frequency measurement: 1/(0xFFFF*0.0001) = 0.1526 Hz
	 * Highest frequency measurement: 1/(1*0.0001) = 10000 Hz
	 */
	if(HAL_TIM_IC_Start_DMA(htim16, TIM_CHANNEL_1, (uint32_t*)input_capture1, 2) != HAL_OK)
		Error_Handler();
	if(HAL_TIM_IC_Start_DMA(htim17, TIM_CHANNEL_1, (uint32_t*)input_capture0, 2) != HAL_OK)
		Error_Handler();
}
Det fungerar så att i STM32 så kan man välja Mode: Circular eller Mode: Normal. Circular betyder att efter att DMA har anropats och fyllt arrayerna input_capute0 och input_capute1 så börjar den om igen. Men är den satt i Mode: Normal så anropas bara DMA 1 gång.
Skärmklipp.PNG
Det som händer är att IC för HTIM17 fungerar utmärkt. När jag pulserar med 3.3v på ingången så ser jag olika värden förändras i input_capture0, medan i input_capture1 så förändras det bara 1 gång, sedan händer det inget mer. Jag använder arrayerna för att räkna ut frekvensen. För input_capture1 så blir frevensen alltid 0.156 Hz, dvs en lägsta uppdateringsfrekvensen.

Så varför anropas inte DMA när det ska göras? Någon som kan det där med IC och SDADC för DMA inom STM32?
Du har inte behörighet att öppna de filer som bifogats till detta inlägg.
SvenW
Inlägg: 1116
Blev medlem: 24 april 2007, 16:23:10
Ort: Göteborg

Re: Någon som förstår det där med DMA i STM32?

Inlägg av SvenW »

Ditt problem är nog för svårt för att någon skall kunna svara.

STM har hundratals olika modelller och manualen för de största är på 3000 sidor!
Och de har många olika typer av timerkretsar?
Mängder av onödig komplexitet med andra ord.
Ser dessutom att du använder STMCube.
Någon skrev att det programmet antagligen är framtaget av reklamavdelningen.

Chansen att få svar kanske ökar om du skriver vilken typ av chip du använder och vilka verktyg.. Kompilator, debugger etc. Nulceo eller Discovery eller egen konstuktion?
Hobby eller professionellt?
ToPNoTCH
Inlägg: 4847
Blev medlem: 21 december 2009, 17:59:48

Re: Någon som förstår det där med DMA i STM32?

Inlägg av ToPNoTCH »

Jag tror du behöver beskriva lite mer vad du egentligen vill åstadkomma.

Jag uppfattar det som att du ursprungligen ville skapa något som kontrollerar om din ADC får ett ändrat värde.
När du sedan fått detta att funka med interrupt så går programmet i interrupt konstant (vilket du i en annan tråd beskriver som
" Detta resulterar att min övriga kod blir lite seg"
Detta är inget konstigt med en 16-bit ADC för du kommer aldrig att ha exakt samma värde vid varje sampling i praktiken (du kommer aldrig ha en stabil spänning på 0.00005V på ingången).

Om du istället beskriver vad du vill uppnå så tror jag det finns smartare sätt att angripa problemet.
Vad gör du med det avlästa värdet exempelvis ? Hur ofta behövs det osv.
Du verkar ha krånglat till det.

Troligen behöver du bara en timer som periodiserat läser av dina ADC.
Du kan använda DMA så finns det "senaste värdet" i minnet hela tiden. Det förenklar men är inte nödvändigt.
Utan cirkulär buffer gör DMA endast en sampling (vilket du upptäckt).
DanielM
Inlägg: 2166
Blev medlem: 5 september 2019, 14:19:58

Re: Någon som förstår det där med DMA i STM32?

Inlägg av DanielM »

SvenW skrev: 13 augusti 2021, 09:26:57 Ditt problem är nog för svårt för att någon skall kunna svara.
Jag tror det också.
STM har hundratals olika modelller och manualen för de största är på 3000 sidor!
Och de har många olika typer av timerkretsar?
Mängder av onödig komplexitet med andra ord.
Ser dessutom att du använder STMCube.
Någon skrev att det programmet antagligen är framtaget av reklamavdelningen.
Ja, detta är nackdelen med STM. Dom är enkla att använda, men kör man fast så är det omöjligt att veta vad som är fel. Till och med STM's egna support har problem med detta.
STMCube är helt underbart.
Chansen att få svar kanske ökar om du skriver vilken typ av chip du använder och vilka verktyg.. Kompilator, debugger etc. Nulceo eller Discovery eller egen konstuktion?
Hobby eller professionellt?
Jag använder STM32F373VBTx mikrokontroller och det är det enda man behöver veta.
ToPNoTCH skrev: 13 augusti 2021, 11:36:31 Jag tror du behöver beskriva lite mer vad du egentligen vill åstadkomma.
Det jag vill göra, är att kunna fylla arrayerna med värden igenom DMA. Men DMA verkar inte anropas.
Jag uppfattar det som att du ursprungligen ville skapa något som kontrollerar om din ADC får ett ändrat värde.
När du sedan fått detta att funka med interrupt så går programmet i interrupt konstant (vilket du i en annan tråd beskriver som
" Detta resulterar att min övriga kod blir lite seg"
Detta är inget konstigt med en 16-bit ADC för du kommer aldrig att ha exakt samma värde vid varje sampling i praktiken (du kommer aldrig ha en stabil spänning på 0.00005V på ingången).
Exakt. Därför måste jag ha DMA. Annars så blir det tokigt.
Om du istället beskriver vad du vill uppnå så tror jag det finns smartare sätt att angripa problemet.
Vad gör du med det avlästa värdet exempelvis ? Hur ofta behövs det osv.
Du verkar ha krånglat till det.
Det jag vill uppnå är att inte använda interrupt när det kommer till IC och SDADC.
Det jag gör med det avlästa värdet så kommer jag spara det i en fil via SD-kort.
Troligen behöver du bara en timer som periodiserat läser av dina ADC.
Du kan använda DMA så finns det "senaste värdet" i minnet hela tiden. Det förenklar men är inte nödvändigt.
Utan cirkulär buffer gör DMA endast en sampling (vilket du upptäckt).
För SDADC så kan man inte ha en timer som triggar på tid. Man måste ha en timer som triggar om det sker ett förändrat värde. Capture Compare.
Det jag tycker är lustigt är att jag har 2 IC, men bara 1 IC gör en cirkulär skrivning, medan den andra gör en normal skrivning, dvs bara 1 gång.
Trots detta så är koden det samma, bara olika minnesadresser t.ex. htim17 och htim16. Då börjar man undra om STM har en bugg.

Buggar:
Jag misstänker 2 buggar.

Bugg 1:
Endast htim17 har cirkulär DMA, medan htim16 har normal DMA. Trots att jag har bockat i att båda ska ha cirkulär DMA.

Kod: Markera allt

	if(HAL_TIM_IC_Start_DMA(htim16, TIM_CHANNEL_1, (uint32_t*)input_capture1, 2) != HAL_OK)
		Error_Handler();
	if(HAL_TIM_IC_Start_DMA(htim17, TIM_CHANNEL_1, (uint32_t*)input_capture0, 2) != HAL_OK)
		Error_Handler();
Bugg 2:
När jag aktiverar SDADC med DMA här.

Kod: Markera allt

	if(HAL_SDADC_InjectedStart_DMA(hsdadc1, (uint32_t*)SDADC1_Single, 9) != HAL_OK)
		Error_Handler();
	if(HAL_SDADC_InjectedStart_DMA(hsdadc2, (uint32_t*)SDADC2_Single, 3) != HAL_OK)
		Error_Handler();
	if(HAL_SDADC_InjectedStart_DMA(hsdadc3, (uint32_t*)SDADC3_Differential, 5) != HAL_OK)
		Error_Handler();
Så kommer jag få ett error när jag försöker avaktivera DMA här.

Kod: Markera allt

if(HAL_SDADC_InjectedStop_DMA(handler_sdadc1) != HAL_OK)
			Error_Handler();
if(HAL_SDADC_InjectedStop_DMA(handler_sdadc2) != HAL_OK)
			Error_Handler();
if(HAL_SDADC_InjectedStop_DMA(handler_sdadc3) != HAL_OK)
			Error_Handler();
Orsaken har med att denna kod.

Kod: Markera allt

HAL_StatusTypeDef HAL_SDADC_InjectedStop_DMA(SDADC_HandleTypeDef *hsdadc)
{
  HAL_StatusTypeDef status;

  /* Check parameters */
  assert_param(IS_SDADC_ALL_INSTANCE(hsdadc->Instance));

  /* Check SDADC state */
  if((hsdadc->State != HAL_SDADC_STATE_INJ) && \
     (hsdadc->State != HAL_SDADC_STATE_REG_INJ))
  {
    /* Return error status */
    status = HAL_ERROR;
  }
  else
  {
    /* Clear JDMAEN bit in SDADC_CR1 register */
    hsdadc->Instance->CR1 &= ~(SDADC_CR1_JDMAEN);

    /* Stop current DMA transfer */
    if(HAL_DMA_Abort(hsdadc->hdma) != HAL_OK) <<<<<<<<<<<<<<----------------------HÄR
    {
      /* Set SDADC in error state */
      hsdadc->State = HAL_SDADC_STATE_ERROR;
      status = HAL_ERROR;
    }
Så verkar HAL_DMA_Abort retunera HAL_ERROR för att hdma->State är HAL_DMA_STATE_READY. Alltså betyder detta att DMA för SDADC....inte var aktiverad redan från början?

Kod: Markera allt

HAL_StatusTypeDef HAL_DMA_Abort(DMA_HandleTypeDef *hdma)
{
  if(hdma->State != HAL_DMA_STATE_BUSY)
  {
    /* no transfer ongoing */
    hdma->ErrorCode = HAL_DMA_ERROR_NO_XFER;
    
    /* Process Unlocked */
    __HAL_UNLOCK(hdma);
    
    return HAL_ERROR;
  }
Senast redigerad av DanielM 14 augusti 2021, 14:27:09, redigerad totalt 2 gånger.
Användarvisningsbild
AndLi
Inlägg: 17043
Blev medlem: 11 februari 2004, 18:17:59
Ort: Knivsta
Kontakt:

Re: Någon som förstår det där med DMA i STM32?

Inlägg av AndLi »

Buggar ligger sannolikt i hal:en.

Ta datablad och pausa din kod och kontrollera vilka värd registren har och om det stämmer med vad de borde ha...

Eller läs in dig på de moduler du vill använda och sätt registren själv. Du har helt enkelt nått den punkt nu när stmcube inte längre hjälper dig.
DanielM
Inlägg: 2166
Blev medlem: 5 september 2019, 14:19:58

Re: Någon som förstår det där med DMA i STM32?

Inlägg av DanielM »

Jag ska gräva lite och kolla vilka register som sätts.
Jag frågade STM32 om vad dom rekommenderar, sätta register själv som en klassisk hårdkodare, eller använda deras HAL.
Dom rekommenderade CubeMX. Dvs autogenerad HAL.
Jag håller med dom. Maskingenererad kod är väldigt strikt och följer mer som en standard för att programmerare. Men HAL-koden ska ju göra rätt också :)
ToPNoTCH
Inlägg: 4847
Blev medlem: 21 december 2009, 17:59:48

Re: Någon som förstår det där med DMA i STM32?

Inlägg av ToPNoTCH »

Så du tänker dig att läsa av en 16-bit ADC och spara varje ändrat värde till SD kort (vid varje förändring) ?
Användarvisningsbild
AndLi
Inlägg: 17043
Blev medlem: 11 februari 2004, 18:17:59
Ort: Knivsta
Kontakt:

Re: Någon som förstår det där med DMA i STM32?

Inlägg av AndLi »

Fast Halen är skriven av en människa och har buggar särskilt om du börjar göra saker mer avancerade eller icke standard.
Såklart säger st att du ska använda cube, de vill ju låsa in dig till deras uC. Har du koll på all kod kan du ju byta till en konkurent... singel source är ju vad leverantörerna gillar, så de kan sätta de priser de vill...
DanielM
Inlägg: 2166
Blev medlem: 5 september 2019, 14:19:58

Re: Någon som förstår det där med DMA i STM32?

Inlägg av DanielM »

ToPNoTCH skrev: 14 augusti 2021, 14:54:33 Så du tänker dig att läsa av en 16-bit ADC och spara varje ändrat värde till SD kort (vid varje förändring) ?
Det blir kanske 1 varje 20ms ungefär. Eller mer.
Jag kan använda en interrupt. Men jag tänkte att varför använda interrupt om DMA finns?
AndLi skrev: 14 augusti 2021, 15:08:02 Fast Halen är skriven av en människa och har buggar särskilt om du börjar göra saker mer avancerade eller icke standard.
Såklart säger st att du ska använda cube, de vill ju låsa in dig till deras uC. Har du koll på all kod kan du ju byta till en konkurent... singel source är ju vad leverantörerna gillar, så de kan sätta de priser de vill...
Men med Cube så underlättar det. Jag skulle aldrig välja en produkt där jag måste läsa 2000 sidor datablad dagligen för att få DMA att fungera, om det finns produkter där jag kan göra det grafiskt utan att ens läsa datablad. Jag vet att vissa företag går mer och mer över till STM32 och vissa företag väljer till och med bygga sina produkter på Arduino. Detta låter lite oseriöst, men så här blir det när marknaden ställer krav på mer och mer avancerade tekniker, samt att det inte får kosta någon tid.
Användarvisningsbild
AndLi
Inlägg: 17043
Blev medlem: 11 februari 2004, 18:17:59
Ort: Knivsta
Kontakt:

Re: Någon som förstår det där med DMA i STM32?

Inlägg av AndLi »

Det är nog inte ens 100 sidor för dma, men kör du vidare på cube, det verkar ju funka så bra för dig .
DanielM
Inlägg: 2166
Blev medlem: 5 september 2019, 14:19:58

Re: Någon som förstår det där med DMA i STM32?

Inlägg av DanielM »

Jag har granskat lite i koden och det verkar dock inte vara funktionerna som är fel på.
Med tanke på att jag kan aktivera cirkulär DMA för IC1 men trots att jag väljer cirkulär DMA för IC2, så blir det ändå normal DMA för IC2. Alltså måste detta betyda det är själva #define och enums som är fel på.

Nu har jag hittat något roligt.
När jag skapade min timer 16 och 17 och aktiverade DMA för dessa. Då fick jag dessa. Jag har sökt vad _up står för, men det står inte i referensmanualen.

Kod: Markera allt

SDADC_HandleTypeDef hsdadc1;
SDADC_HandleTypeDef hsdadc2;
SDADC_HandleTypeDef hsdadc3;
DMA_HandleTypeDef hdma_sdadc1;
DMA_HandleTypeDef hdma_sdadc2;
DMA_HandleTypeDef hdma_sdadc3;

TIM_HandleTypeDef htim16;
TIM_HandleTypeDef htim17;
DMA_HandleTypeDef hdma_tim16_ch1_up;
DMA_HandleTypeDef hdma_tim17_ch1_up;
Dessa DMA_HandleTypeDef verkar inte användas till något.
hummel
Inlägg: 2259
Blev medlem: 28 november 2009, 10:40:52
Ort: Stockholm

Re: Någon som förstår det där med DMA i STM32?

Inlägg av hummel »

Jag använde en 373:a i ett projekt i höstas där jag använde DMA för att läsa av ADC, tyckte inte det var speciellt krångligt, helt ok beskrivet i referensmanualen, jag skrev koden själv utan kodgenereringsverktyg.
ToPNoTCH
Inlägg: 4847
Blev medlem: 21 december 2009, 17:59:48

Re: Någon som förstår det där med DMA i STM32?

Inlägg av ToPNoTCH »

DanielM skrev: 14 augusti 2021, 15:28:09
ToPNoTCH skrev: 14 augusti 2021, 14:54:33 Så du tänker dig att läsa av en 16-bit ADC och spara varje ändrat värde till SD kort (vid varje förändring) ?
Det blir kanske 1 varje 20ms ungefär. Eller mer.
Jag kan använda en interrupt. Men jag tänkte att varför använda interrupt om DMA finns?
Vad får det att bli 20ms ?
ToPNoTCH
Inlägg: 4847
Blev medlem: 21 december 2009, 17:59:48

Re: Någon som förstår det där med DMA i STM32?

Inlägg av ToPNoTCH »

Varför har du DMA på Tim16 & 17 ?
Det är väl ADC du skall ha värdet ifrån inte Timers.

DMA_HandleTypeDef hdma_tim16_ch1_up;
DMA_HandleTypeDef hdma_tim17_ch1_up;
Är för att du använder DMA på dessa.

Sen är jag nyfiken på hur du triggar ADC1 (där kan man väl inte välja Timer som extern trigger).
DanielM
Inlägg: 2166
Blev medlem: 5 september 2019, 14:19:58

Re: Någon som förstår det där med DMA i STM32?

Inlägg av DanielM »

hummel skrev: 14 augusti 2021, 20:16:48 Jag använde en 373:a i ett projekt i höstas där jag använde DMA för att läsa av ADC, tyckte inte det var speciellt krångligt, helt ok beskrivet i referensmanualen, jag skrev koden själv utan kodgenereringsverktyg.
Då betyder det att deras referensmanual är också korrekt.
Det problem jag har med när det kommer till att sätta register...vart börjar man liksom? Hur är man säker på att man gör rätt?
ToPNoTCH skrev: 14 augusti 2021, 20:22:48
DanielM skrev: 14 augusti 2021, 15:28:09
ToPNoTCH skrev: 14 augusti 2021, 14:54:33 Så du tänker dig att läsa av en 16-bit ADC och spara varje ändrat värde till SD kort (vid varje förändring) ?
Det blir kanske 1 varje 20ms ungefär. Eller mer.
Jag kan använda en interrupt. Men jag tänkte att varför använda interrupt om DMA finns?
Vad får det att bli 20ms ?
Jag höftade bara. Jag vill helst kunna läsa minst 1 gång varje millisekund. Men sådant tar rätt mycket processorkrafter.
ToPNoTCH skrev: 14 augusti 2021, 21:03:27 Varför har du DMA på Tim16 & 17 ?
Det är väl ADC du skall ha värdet ifrån inte Timers.

DMA_HandleTypeDef hdma_tim16_ch1_up;
DMA_HandleTypeDef hdma_tim17_ch1_up;
Är för att du använder DMA på dessa.

Sen är jag nyfiken på hur du triggar ADC1 (där kan man väl inte välja Timer som extern trigger).
För att jag använder TIM16 och TIM17 som Input Capture. I DMA så sparar jag räknevärdet. Notera att jag har både problem med Input Capture DMA och SDADC DMA.

Jag triggar alla SDADC:er igenom TIM12 och TIM13.
Skriv svar