petrdynin

Mik32+4Ch_ADC+Timer32_IRQ+DMA+2xBuffer

Sep 24th, 2025 (edited)
123
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 10.30 KB | Source Code | 0 0
  1. #include "mik32_hal_irq.h"
  2. #include "mik32_hal_adc.h"
  3. #include "mik32_hal_timer32.h"
  4. #include "mik32_hal_dma.h"
  5.  
  6.  
  7. /* Пример работы запуска преобразований ADC по таймеру, каналы запускаются по таймерe по кольцу Ch0-Ch1-Ch2-Ch3
  8.  * полученные данные по DMA складываются в текущий буфер, при заполнении текущего буфера в прерывании от DMA
  9.  * переключаемся на свободный буфер и DMA начинает складывать новые данные в него,
  10.  * а в это время программа может обрабатывает заполненный буфер (усреднение и округление).
  11.  */
  12.  
  13.  
  14. ADC_HandleTypeDef hadc;
  15. TIMER32_HandleTypeDef htimer32_1;
  16. DMA_InitTypeDef hdma;
  17. DMA_ChannelHandleTypeDef hdma_ch0;
  18.  
  19.  
  20.  
  21. #define _ADC_SEL_CHANNEL(channel_selection) ({                                                                        \
  22.         ANALOG_REG->ADC_CONFIG   = (((ANALOG_REG)->ADC_CONFIG & (~ADC_CONFIG_SAH_TIME_READ_M)) & (~ADC_CONFIG_SEL_M)) \
  23.                                  | (((ANALOG_REG)->ADC_CONFIG >> 1) & ADC_CONFIG_SAH_TIME_WRITE_M)                    \
  24.                                  | ((channel_selection) << ADC_CONFIG_SEL_S); })
  25.  
  26. /*
  27.  * SAH_TIME > 350*10E-9 * Fahb, тогда при максимальной частоте 32 МГц
  28.  * SAH_TIME > 350*10E-9 * 32 * 10E6 = 11,2.Тогда min SAH_TIME = 12 (0xc)
  29.  * SAH_TIME = 0xC...0x3F - допустимый диапазон при 32 МГц
  30.  * SAH_TIME = 0x1...0x3F - максимальная частота Fahb = 2,85 МГц, когда можно делать SAH_TIME = 0x1
  31. */
  32. #define SAH_TIME   0x3F
  33. #define _ADC_SAH_TIME(sah_time) ({                                                                                     \
  34.         ANALOG_REG->ADC_CONFIG  = (ANALOG_REG->ADC_CONFIG & (~ADC_CONFIG_SAH_TIME_READ_M))                            \
  35.                                  | ((sah_time) << ADC_CONFIG_SAH_TIME_WRITE_S); })
  36.  
  37.  
  38. void SystemClock_Config(void);
  39. void GPIO_Init();
  40. static void ADC_Init(void);
  41. static void Timer32_1_Init(void);
  42. static void DMA_Init(void);
  43. static void DMA_CH0_Init(DMA_InitTypeDef *hdma);
  44.  
  45. #define BUFF_SIZE  32    // размер должен быть степенью двойки
  46.  
  47.  
  48. volatile uint16_t adc_value[4], adc_ch[4], cnt = 0;
  49. volatile uint8_t flag_dma = 0, CurBuf = 0,  buf_ready = 0, buff_fill = 0;
  50. volatile uint16_t buff[2][BUFF_SIZE];
  51. volatile uint16_t avg[4];
  52.  
  53. int main()
  54. {
  55.  
  56.     PM->CLK_APB_M_SET = PM_CLOCK_APB_M_PAD_CONFIG_M | PM_CLOCK_APB_M_EPIC_M;
  57.  
  58.     GPIO_Init();
  59.  
  60.     DMA_Init();
  61.  
  62.     Timer32_1_Init();
  63.  
  64.  
  65.     ADC_Init();
  66.     _ADC_SAH_TIME(SAH_TIME);
  67.     _ADC_SEL_CHANNEL(2);
  68.  
  69.  
  70.     HAL_EPIC_MaskLevelSet(HAL_EPIC_TIMER32_1_MASK);
  71.     HAL_IRQ_EnableInterrupts();
  72.  
  73.  
  74.     HAL_DMA_Start(&hdma_ch0, (void *)&ANALOG_REG->ADC_VALUE, (void *)buff[CurBuf], BUFF_SIZE*2 - 1);
  75.  
  76.  
  77.     /* Запуск таймера и прерываний в продолжительном режиме */
  78.     HAL_Timer32_Start_IT(&htimer32_1, TIMER32_INT_OVERFLOW_M);
  79.  
  80.  
  81.     while (1)
  82.        {
  83.  
  84.         if(flag_dma){
  85.             flag_dma = 0;
  86.             cnt++;
  87.             if(cnt > 10){
  88.                 cnt = 0;
  89.             }
  90.  
  91.  
  92.             HAL_DMA_Start(&hdma_ch0, (void *)&ANALOG_REG->ADC_VALUE, (void *)buff[CurBuf], BUFF_SIZE*2 - 1);
  93.            // тут обрабатываем заполненный буфер buff[buff_fill], пока текущий buff[CurBuf] наполняется данными
  94.             for(int channel = 0; channel < 4; channel++) {
  95.                 int32_t sum = 0;  // Накопитель большего размера
  96.                 for(int sample = 0; sample < 8; sample++) {
  97.                     sum += buff[buff_fill][channel + sample * 4];
  98.                   }
  99.                 avg[channel] = (sum + 4) >> 3;  // Целочисленное деление
  100.                 }
  101.              GPIO_0->OUTPUT ^= 1<<9;
  102.         }
  103.     }
  104. }
  105.  
  106. void SystemClock_Config(void)
  107. {
  108.     PCC_InitTypeDef PCC_OscInit = {0};
  109.  
  110.     PCC_OscInit.OscillatorEnable = PCC_OSCILLATORTYPE_ALL;
  111.     PCC_OscInit.FreqMon.OscillatorSystem = PCC_OSCILLATORTYPE_OSC32M;
  112.     PCC_OscInit.FreqMon.ForceOscSys = PCC_FORCE_OSC_SYS_UNFIXED;
  113.     PCC_OscInit.FreqMon.Force32KClk = PCC_FREQ_MONITOR_SOURCE_OSC32K;
  114.     PCC_OscInit.AHBDivider = 0;
  115.     PCC_OscInit.APBMDivider = 0;
  116.     PCC_OscInit.APBPDivider = 0;
  117.     PCC_OscInit.HSI32MCalibrationValue = 128;
  118.     PCC_OscInit.LSI32KCalibrationValue = 8;
  119.     PCC_OscInit.RTCClockSelection = PCC_RTC_CLOCK_SOURCE_AUTO;
  120.     PCC_OscInit.RTCClockCPUSelection = PCC_CPU_RTC_CLOCK_SOURCE_OSC32K;
  121.     HAL_PCC_Config(&PCC_OscInit);
  122. }
  123.  
  124. void GPIO_Init()
  125. {
  126.     GPIO_InitTypeDef GPIO_InitStruct = {0};
  127.     __HAL_PCC_GPIO_0_CLK_ENABLE();
  128.     __HAL_PCC_GPIO_1_CLK_ENABLE();
  129.     __HAL_PCC_GPIO_2_CLK_ENABLE();
  130.  
  131.     GPIO_InitStruct.Pin = GPIO_PIN_9 | GPIO_PIN_10 ;
  132.     GPIO_InitStruct.Mode = HAL_GPIO_MODE_GPIO_OUTPUT;
  133.     GPIO_InitStruct.Pull = HAL_GPIO_PULL_NONE;
  134.     HAL_GPIO_Init(GPIO_0, &GPIO_InitStruct);
  135.  
  136.  
  137.     //Канал 0 и 1
  138.     GPIO_InitStruct.Pin = GPIO_PIN_5 | GPIO_PIN_7;
  139.     GPIO_InitStruct.Mode = HAL_GPIO_MODE_ANALOG;
  140.     GPIO_InitStruct.Pull = HAL_GPIO_PULL_NONE;
  141.     HAL_GPIO_Init(GPIO_1, &GPIO_InitStruct);
  142.  
  143.     //Канал 2 и 3
  144.     GPIO_InitStruct.Pin = GPIO_PIN_2 | GPIO_PIN_4;
  145.     GPIO_InitStruct.Mode = HAL_GPIO_MODE_ANALOG;
  146.     GPIO_InitStruct.Pull = HAL_GPIO_PULL_NONE;
  147.     HAL_GPIO_Init(GPIO_0, &GPIO_InitStruct);
  148.  
  149. }
  150.  
  151.  
  152. void __attribute__((section(".ram_text"))) trap_handler(void)
  153. {
  154.     if(EPIC_CHECK_DMA()){
  155.         HAL_DMA_ClearIrq(&hdma);
  156.  
  157.         buff_fill = CurBuf;
  158.         CurBuf = 1 - CurBuf;
  159.         flag_dma = 1;
  160.     }
  161.  
  162.     if (EPIC_CHECK_TIMER32_1())
  163.         {
  164.             static uint8_t n = 3, k=0;
  165.  
  166.             if ((TIMER32_1->INT_FLAGS & TIMER32_INT_OVERFLOW_M) & TIMER32_1->INT_MASK)
  167.               {
  168.                  while (!(ANALOG_REG->ADC_VALID));
  169.                  if(k < 4){
  170.                      adc_value[k] = ANALOG_REG->ADC_VALUE;
  171.                      adc_ch[k] = (ANALOG_REG->ADC_CONFIG & (7<<4)) >> 4;
  172.                      k++;
  173.                  }
  174.                
  175.                 /* Измерение времени преобразования с asm вставкой
  176.                     __asm__ volatile (
  177.  
  178.  
  179.                         "li t0, 0x85044             \n\t"   // ADC_SINGLE
  180.                         "li t1, 1                   \n\t"
  181.                         "sw t1, 0(t0)               \n\t"   // Запуск АЦП
  182.  
  183.                         "li t0, 0x84000             \n\t"   // GPIO_SET
  184.                         "li t1, 0x00000400          \n\t"   // PIN_10
  185.                         "sw t1, 0(t0)               \n\t"   // START
  186.  
  187.                         "li t0, 0x85048             \n\t"   // ADC_VALID
  188.                         "1: lw t1, 0(t0)            \n\t"
  189.                         "beqz t1, 1b                \n\t"   // Ожидание
  190.  
  191.                         "li t0, 0x84004             \n\t"   // GPIO_CLEAR
  192.                         "li t1, 0x00000400          \n\t"
  193.                         "sw t1, 0(t0)               \n\t"   // STOP
  194.                         ::: "t0", "t1", "memory"
  195.                        );
  196.                 */
  197.                
  198.                  ANALOG_REG->ADC_SINGLE = 1;
  199.                  #if(SAH_TIME > 0xF)
  200.                  // при большом SAH_TIME задуманный ранее к переключению канал
  201.                  // может не успеть защелкнуться, и вместо него запишется следующий канал
  202.                     for(uint8_t i=0; i<12; i++)
  203.                        asm("nop");
  204.                  //**********************************************
  205.                  #endif
  206.                  _ADC_SEL_CHANNEL(n);
  207.                  n++;
  208.                  n &= 3;
  209.                  GPIO_0->OUTPUT ^= GPIO_PIN_10;
  210.               }
  211.           TIMER32_1->INT_CLEAR = TIMER32_INTERRUPT_CLEAR_MASK;
  212.         }
  213. }
  214.  
  215. static void ADC_Init(void)
  216. {
  217.     hadc.Instance = ANALOG_REG;
  218.  
  219.     hadc.Init.Sel    = ADC_CHANNEL1;
  220.     hadc.Init.EXTRef = ADC_EXTREF_OFF;    /* Выбор источника опорного напряжения: «1» - внешний; «0» - встроенный */
  221.     hadc.Init.EXTClb = ADC_EXTCLB_ADCREF; /* Выбор источника внешнего опорного напряжения: «1» - внешний вывод; «0» - настраиваемый ОИН */
  222.  
  223.     HAL_ADC_Init(&hadc);
  224. }
  225.  
  226.  
  227. static void Timer32_1_Init(void)
  228. {
  229.     htimer32_1.Instance = TIMER32_1;
  230.     htimer32_1.Top = 800000;
  231.     htimer32_1.Clock.Source = TIMER32_SOURCE_PRESCALER;
  232.     htimer32_1.Clock.Prescaler = 0;
  233.     htimer32_1.InterruptMask = TIMER32_INT_OVERFLOW_M;
  234.     htimer32_1.CountMode = TIMER32_COUNTMODE_FORWARD;
  235.     HAL_Timer32_Init(&htimer32_1);
  236. }
  237.  
  238. static void DMA_Init(void)
  239. {
  240.  
  241.     /* Настройки DMA */
  242.     hdma.Instance = DMA_CONFIG;
  243.     hdma.CurrentValue = DMA_CURRENT_VALUE_ENABLE;
  244.     HAL_DMA_Init(&hdma);
  245.     HAL_DMA_GlobalIRQEnable(&hdma, DMA_IRQ_ENABLE);
  246.     /* Инициализация канала */
  247.     DMA_CH0_Init(&hdma);
  248.     HAL_DMA_LocalIRQEnable(&hdma_ch0, DMA_IRQ_ENABLE);
  249. }
  250.  
  251. static void DMA_CH0_Init(DMA_InitTypeDef *hdma)
  252. {
  253.     hdma_ch0.dma = hdma;
  254.  
  255.     /* Настройки канала */
  256.     hdma_ch0.ChannelInit.Channel = DMA_CHANNEL_0;
  257.     hdma_ch0.ChannelInit.Priority = DMA_CHANNEL_PRIORITY_VERY_HIGH;
  258.  
  259.     hdma_ch0.ChannelInit.ReadMode = DMA_CHANNEL_MODE_PERIPHERY;
  260.     hdma_ch0.ChannelInit.ReadInc = DMA_CHANNEL_INC_DISABLE;
  261.     hdma_ch0.ChannelInit.ReadSize = DMA_CHANNEL_SIZE_HALFWORD; /* data_len должно быть кратно read_size */
  262.     hdma_ch0.ChannelInit.ReadBurstSize = 1;                    /* read_burst_size должно быть кратно read_size */
  263.     hdma_ch0.ChannelInit.ReadRequest = DMA_CHANNEL_TIMER32_1_REQUEST;
  264.     hdma_ch0.ChannelInit.ReadAck = DMA_CHANNEL_ACK_ENABLE;
  265.  
  266.     hdma_ch0.ChannelInit.WriteMode = DMA_CHANNEL_MODE_MEMORY;
  267.     hdma_ch0.ChannelInit.WriteInc = DMA_CHANNEL_INC_ENABLE;
  268.     hdma_ch0.ChannelInit.WriteSize = DMA_CHANNEL_SIZE_HALFWORD; /* data_len должно быть кратно write_size */
  269.     hdma_ch0.ChannelInit.WriteBurstSize = 1;                /* write_burst_size должно быть кратно read_size */
  270.     hdma_ch0.ChannelInit.WriteRequest = DMA_CHANNEL_TIMER32_1_REQUEST;
  271.     hdma_ch0.ChannelInit.WriteAck = DMA_CHANNEL_ACK_ENABLE;
  272. }
  273.  
  274.  
Add Comment
Please, Sign In to add comment