0
\$\begingroup\$

I have an external ADC with 2 parallel output pins. Each is 1 bit (2 bits total), with clk_out pin.

I am trying to read the parallel pins using a NUCLEO-H743ZI2 (480 Mhz). I followed the AN4666 example to receive the data. clk_out is connected to PA6 which is defined as a TIMER with input capture and it triggers the DMA to GPIO pins and saves it to memory.

Unfortunately my code reads the pins only once and I was expecting that it would read every falling edge of the clk_out. All I am trying to do is make the DMA read every falling edge.

Here is my code.

#include "main.h" /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ #define MAX_FRAME_SIZE 100 #define BUFFER_SIZE 20 #define HALF_BUFFER_SIZE BUFFER_SIZE/2 /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ volatile int LastITHalfComplete = 0; volatile int32_t FullDataIndex = 0; volatile int i = 0; volatile uint8_t transferComplete = 0; /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ TIM_HandleTypeDef htim1; DMA_HandleTypeDef hdma_tim1_ch1; UART_HandleTypeDef huart3; PCD_HandleTypeDef hpcd_USB_OTG_FS; /* USER CODE BEGIN PV */ static uint8_t aFull_Buffer[MAX_FRAME_SIZE] = {0}; static uint8_t aDST_Buffer[BUFFER_SIZE] = {0}; /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_USART3_UART_Init(void); static void MX_USB_OTG_FS_PCD_Init(void); static void MX_TIM1_Init(void); static void MX_DMA_Init(void); /* USER CODE BEGIN PFP */ static void TransferComplete(DMA_HandleTypeDef *hdma_tim1_ch1); static void TransferError(DMA_HandleTypeDef *hdma_tim1_ch1); static void HalfTransferComplete(DMA_HandleTypeDef *hdma_tim1_ch1); /* USER CODE END PFP */ /* Private user code */ /* USER CODE BEGIN 0 */ /* USER CODE END 0 */ /** * @brief The application entry point. * @retval int */ int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_USART3_UART_Init(); MX_USB_OTG_FS_PCD_Init(); MX_TIM1_Init(); MX_DMA_Init(); /* USER CODE BEGIN 2 */ // Attach DMA callback functions htim1.hdma[TIM_DMA_ID_CC1]->XferHalfCpltCallback = HalfTransferComplete; htim1.hdma[TIM_DMA_ID_CC1]->XferCpltCallback = TransferComplete; htim1.hdma[TIM_DMA_ID_CC1]->XferErrorCallback = TransferError; // Start DMA in interrupt mode, specify source and destination HAL_DMA_Start_IT(htim1.hdma[TIM_DMA_ID_CC1], (uint32_t) &GPIOC->IDR, (uint32_t) &aDST_Buffer, 1); // Enable timer to trigger DMA transfer - CC1DE bit __HAL_TIM_ENABLE_DMA(&htim1, TIM_DMA_CC1); // Enable timer input capture HAL_TIM_IC_Start(&htim1, TIM_CHANNEL_1); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ /* USER CODE BEGIN WHILE */ while (1) { //if (transferComplete) { //transferComplete = 0; // Transmit buffer to UART // Prepare data into buffer //HAL_UART_Transmit_IT(&huart3, buff, LEN); //} /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ } 

The interrupts:

 /* USER CODE BEGIN 4 */ static void HalfTransferComplete(DMA_HandleTypeDef *hdma_tim1_ch1) { int position = 0; LastITHalfComplete = 1; /*Copy the first part of the received buffer */ for (int i = 0; i < HALF_BUFFER_SIZE; i++) { aFull_Buffer[FullDataIndex] = aDST_Buffer[i+position]; FullDataIndex++; HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_1); } } static void TransferComplete(DMA_HandleTypeDef *hdma_tim1_ch1) { int position = HALF_BUFFER_SIZE; LastITHalfComplete = 0; /* Copy the second part of the received buffer */ for (int i = 0; i < HALF_BUFFER_SIZE; i++) { aFull_Buffer[FullDataIndex] = aDST_Buffer[i+position]; FullDataIndex++; HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0); } transferComplete = 1;} static void TransferError(DMA_HandleTypeDef *hdma_tim1_ch1) { HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_14); } void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart3) { // Enable again DMA for a new transfer HAL_DMA_Start_IT(htim1.hdma[TIM_DMA_ID_CC1], (uint32_t) &GPIOC->IDR, (uint32_t) aDST_Buffer, BUFFER_SIZE); } 
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

The direct answer to your question is that you need to clear the capture flag (TIMx_SR_CCxIF) before you can capture again. The normal way to do this is by reading the capture register TIMx_CCxR.

However, the real answer is that you are doing it all wrong!

The application note that you have referred to is performing parallel output with a timer output for the clock and timer-driven DMA to GPIO for the data. This is ok because you are in control of the clock.

Trying to do parallel input like this is not going to work. The problem is there will be a large (and variable) latency between the clock edge and the input data being read.

Another problem is that it will be very processor intensive, requiring an interrupt for every active clock edge. The reason for this is that in normal timer input capture with DMA, the DMA reads the value that the timer captured from the TIMx_CCxR register, and reading this register clears the capture flag. This means that another capture can occur without involving the processor. Since you want the DMA to do something else (read the GPIO) you will have to also trigger an interrupt to clear the flag in software.

If your clock is so slow that you can tolerate a large and variable latency before reading the data, and your processor load is light enough that you can tolerate an interrupt every active edge, then save yourself some hassle and just use an EXTI interrupt on the clock and read the GPIO in the interrupt. This avoids using either a timer or DMA, so your code will be ten times simpler.

If you can't tolerate the latency or the processor load, then you need to use some kind of parallel synchronous input, for example the digital camera interface.

Since you only have two data lines, then maybe you could even try to use two serial synchronous inputs, for example two SPIs, with both their clocks connected to the same signal. This is a bit hacky, but might be simpler that using the DCMI.

\$\endgroup\$
2
  • \$\begingroup\$ thank you for the feedback Tom, actually I have 5 ADC output (2bit CH1(I0,I1) and 2bit CH2(Q0,Q1)) and 1 clk_out. I have tried to work with the DCMI I even wrote a code but it did not work. \$\endgroup\$ Commented Sep 12, 2022 at 5:29
  • \$\begingroup\$ the ADC the sampling speed that I am working with could be from 4-16MSPS. \$\endgroup\$ Commented Sep 12, 2022 at 5:30

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.