0
votes

I want to configure ADC with DMA on STM32(Nucleo-F401RE) and transmit the values through SPI to Basys 3 FPGA. Before transmission through SPI, when i read the values in memory realtime using STMSTudio, it is erratic.

In the past,I have tried increasing the sampling cycles, the issue persists. Configured ADC without DMA with HAL_ADC_Start function and transferred the values to PC through UART, unable to retrieve the original signal. I'm unable to isolate where the problem lies.

uint32_t ADC1ConvertedValues[100];

int main(void) {
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_ADC1_Init();
  MX_SPI1_Init();


  while (1) {
    HAL_GPIO_WritePin(GPIOA,GPIO_PIN_9,GPIO_PIN_SET);
    if (HAL_ADC_Start_DMA(&hadc1, (uint32_t*)ADC1ConvertedValues, 100) ==         HAL_OK) {

      HAL_GPIO_WritePin(GPIOA,GPIO_PIN_9,GPIO_PIN_RESET);   
      HAL_SPI_Transmit(&hspi1,(uint8_t*)(ADC1ConvertedValues),4,1);
      HAL_GPIO_WritePin(GPIOA,GPIO_PIN_9,GPIO_PIN_SET);
    }
  }
}

void SystemClock_Config(void) {
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};


  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);

  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = 16;
  RCC_OscInitStruct.PLL.PLLN = 336;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;
  RCC_OscInitStruct.PLL.PLLQ = 7;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
    Error_Handler();
  }

  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                          |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) {
    Error_Handler();
  }
}

static void MX_ADC1_Init(void) {
  ADC_ChannelConfTypeDef sConfig = {0};


  hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
  hadc1.Init.Resolution = ADC_RESOLUTION_8B;
  hadc1.Init.ScanConvMode = ENABLE;
  hadc1.Init.ContinuousConvMode = ENABLE;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc1.Init.NbrOfConversion = 1;
  hadc1.Init.DMAContinuousRequests = ENABLE;
  hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  if (HAL_ADC_Init(&hadc1) != HAL_OK) {
    Error_Handler();
  }

  sConfig.Channel = ADC_CHANNEL_0;
  sConfig.Rank = 1;
  sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) {
    Error_Handler();
  }  
}

static void MX_SPI1_Init(void) {

  /* SPI1 parameter configuration*/
  hspi1.Instance = SPI1;
  hspi1.Init.Mode = SPI_MODE_MASTER;
  hspi1.Init.Direction = SPI_DIRECTION_2LINES;
  hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi1.Init.NSS = SPI_NSS_SOFT;
  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi1.Init.CRCPolynomial = 10;
  if (HAL_SPI_Init(&hspi1) != HAL_OK) {
    Error_Handler();
  }
}


static void MX_DMA_Init(void)  {

  __HAL_RCC_DMA2_CLK_ENABLE();
  HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
}


static void MX_GPIO_Init(void) {
  GPIO_InitTypeDef GPIO_InitStruct = {0};  
  __HAL_RCC_GPIOA_CLK_ENABLE();
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, GPIO_PIN_RESET);


  GPIO_InitStruct.Pin = GPIO_PIN_9;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

}
void Error_Handler(void) {
}

#ifdef  USE_FULL_ASSERT

void assert_failed(uint8_t *file, uint32_t line) { 

#endif /* USE_FULL_ASSERT */

EDIT 1: I used the arduino IDE to program NUCLEO-f401 RE and below is the code used :

 #include <f401reMap.h>

float analogPin = pinMap(31); //PA0

float val = 0;  // variable to store the value read

void setup() {
  Serial.begin(115200); //  setup serial
  analogReadResolution(12);

}

void loop() {
  val = analogRead(analogPin);  // read the input pin
  Serial.println(val);          // debug value
}

It works for input signal frequency below 100Hz. How do I increase the throughput rate? My project requires conversion of analog signal between 500KHz to 900Khz.

1

1 Answers

0
votes

Tried changing the DMA buffer size/speed uint32_t ADC1ConvertedValues[100]; reading about the DMA for this chip for my project I found that this sets the size of memory direct memory access allocated samples per clock? If it was I2C or if you would like to read about the timing concepts keep reading You need to find the ADC registers that set the spi baud rate and account for the setup requirements or re-initialization.

hadc1.Instance = ADC1;// this selects analog to digital circuit one hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; //"skip" 3 out of 4 clock steps in sync with time scale read on... hadc1.Init.Resolution = ADC_RESOLUTION_8B; //use 8 bits to pack the numbers to send to the intergrated CPU of the f401 Background on the math ADC and DMA are often classifyed in read rate at the spi level not at the analog level. So if the chip can do 8khz spi using 8 bits then we can calculate in bigO (8n+n) time that we should get just under 1khz read speed. HOWEVER you need to write 8 bits to receive 8bits so bigO time is now bigO(n16+n) . But because of continuous register I believe it could be as low as bigO (8n+n+8) or (8n+n+8setupbits). So using that we know the time consumed by the intermediate operations in terms of clock cycles note that the term n alone is to account for assumptions of unknown internal clock trigger conditions and should have a scalar that relative to theta if scale resolution is a absolute requirement. Also keep in mind that these frequencies you may be experiencing noise from impedance resistance and capacitance.