lutunovoleg

lab4

Mar 25th, 2026
29
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 14.30 KB | None | 0 0
  1. // Регистры управления и статуса RISC-V (базовые определения)
  2. #include "riscv_csr_encoding.h"
  3. // Специфичные для ядра SCR1 определения CSR
  4. #include "scr1_csr_encoding.h"
  5. // Карта памяти микроконтроллера (адреса периферии)
  6. #include "mcu32_memory_map.h"
  7. // Менеджер питания и тактирования
  8. #include <power_manager.h>
  9. // Конфигурация выводов (мультиплексирование функций)
  10. #include "pad_config.h"
  11. // Прерывания от GPIO
  12. #include <gpio_irq.h>
  13. // Внешний контроллер прерываний (EPIC)
  14. #include <epic.h>
  15. // Утилиты для работы с CSR регистрами
  16. #include <csr.h>
  17. // Драйвер GPIO
  18. #include <gpio.h>
  19. // Стандартные целочисленные типы
  20. #include <stdint.h>
  21. // Стандартная библиотека (rand, RAND_MAX)
  22. #include <stdlib.h>
  23. // HAL для 16-битного таймера
  24. #include "mik32_hal_timer16.h"
  25. // HAL для контроля тактирования
  26. #include "mik32_hal_pcc.h"
  27. // HAL для ЦАП (не используется в коде, но подключен)
  28. #include "mik32_hal_dac.h"
  29.  
  30. // Указатель на структуру GPIO для порта 0 (используется базовый адрес из карты памяти)
  31. #define GPIO_X ((GPIO_TypeDef*)GPIO_0_BASE_ADDRESS )
  32.  
  33. // Внешняя переменная, определяемая компоновщиком - содержит адрес начала кода программы
  34. // Используется для установки вектора прерываний
  35. extern unsigned long __TEXT_START__;
  36.  
  37. // Флаг переключения между двумя задачами в основном цикле
  38. // Изменяется в обработчике прерывания при нажатии кнопки
  39. int task = 0;
  40.  
  41. // Обработчик прерывания
  42. void trap_handler() {
  43.     if ( EPIC->RAW_STATUS & (1<<EPIC_GPIO_IRQ_INDEX))  // Проверка источника прерывания (прерывание пришло от GPIO?)
  44.     {
  45.         GPIO_0->OUTPUT ^= (0b1)<<(9); // зажигаем зеленый светодиод
  46.         task = ~task;
  47.         GPIO_IRQ->CLEAR = (1 << 7); // Сброс флага прерывания GPIO
  48.         EPIC->CLEAR = (1<<EPIC_GPIO_IRQ_INDEX);   // Сброс флага прерывания порта ввода-вывода
  49.     }
  50. }
  51.  
  52. #define CRC32_POLY 0xEDB88320
  53.  
  54. // Таблица предвычисленных значений для CRC32
  55. uint32_t crc32_table[256];
  56.  
  57. // Счетчик тиков (количество вызовов функции tick_counter)
  58. uint32_t counts_of_tick;
  59.  
  60. // Переменные для вычисления числа π методом Монте-Карло
  61. uint32_t iterations = 1;    // Количество итераций
  62. uint32_t inside = 1;         // Количество точек, попавших внутрь круга
  63. uint32_t pi = 0;             // Вычисленное значение π
  64.  
  65. // ============================================================================
  66. // ФУНКЦИИ ДЛЯ ВЫЧИСЛЕНИЙ
  67. // ============================================================================
  68.  
  69. /**
  70.  * calculate_pi - вычисление числа π методом Монте-Карло
  71.  *
  72.  * Метод: генерируются случайные точки с координатами (x,y) в квадрате [0,1]x[0,1]
  73.  * Подсчитывается количество точек, попавших в круг радиусом 1 (x^2 + y^2 <= 1)
  74.  * π ≈ 4 * (точек_в_круге / всего_точек)
  75.  *
  76.  * @return long - текущее приближение π (целое число, что некорректно)
  77.  */
  78. long calculate_pi(){
  79.     // Генерация случайных координат в диапазоне [0, 1]
  80.     float x = (float)rand() / RAND_MAX;
  81.     float y = (float)rand() / RAND_MAX;
  82.    
  83.     // Проверка попадания точки в круг
  84.     if ((x*x+y*y) <= 1.0f) inside++;
  85.    
  86.     // Вычисление приближения π
  87.     pi = 4.0f * inside / iterations;
  88.    
  89.     // Увеличение счетчика итераций
  90.     iterations++;
  91.    
  92.     return pi;  // Возврат целого числа (должен быть float/double)
  93. }
  94.  
  95. /**
  96.  * tick_counter - простой счетчик вызовов
  97.  * Увеличивает глобальный счетчик и возвращает его значение
  98.  *
  99.  * @return uint32_t - текущее значение счетчика
  100.  */
  101. uint32_t tick_counter() {
  102.     counts_of_tick++;
  103.     return counts_of_tick;
  104. }
  105.  
  106. // ============================================================================
  107. // НАСТРОЙКА ТАЙМЕРА
  108. // ============================================================================
  109.  
  110. // Дескриптор таймера Timer16_1 (структура с настройками)
  111. Timer16_HandleTypeDef htimer16_1;
  112.  
  113. /**
  114.  * SystemClock_Config - настройка системной частоты
  115.  * Использует HAL для конфигурации генераторов и делителей
  116.  */
  117. void SystemClock_Config(void)
  118. {
  119.     PCC_InitTypeDef PCC_OscInit = {0};
  120.  
  121.     // Включение всех генераторов
  122.     PCC_OscInit.OscillatorEnable = PCC_OSCILLATORTYPE_ALL;
  123.    
  124.     // Выбор основного системного генератора - 32 МГц
  125.     PCC_OscInit.FreqMon.OscillatorSystem = PCC_OSCILLATORTYPE_OSC32M;
  126.    
  127.     // Не фиксировать принудительно системный генератор
  128.     PCC_OscInit.FreqMon.ForceOscSys = PCC_FORCE_OSC_SYS_UNFIXED;
  129.    
  130.     // Источник 32 кГц - внешний или внутренний OSC32K
  131.     PCC_OscInit.FreqMon.Force32KClk = PCC_FREQ_MONITOR_SOURCE_OSC32K;
  132.    
  133.     // Делители шин (0 = деление на 1)
  134.     PCC_OscInit.AHBDivider = 0;      // AHB шина
  135.     PCC_OscInit.APBMDivider = 0;     // APB M шина (периферия)
  136.     PCC_OscInit.APBPDivider = 0;     // APB P шина (периферия)
  137.    
  138.     // Калибровочные значения для внутренних генераторов
  139.     PCC_OscInit.HSI32MCalibrationValue = 128;    // Для 32 МГц
  140.     PCC_OscInit.LSI32KCalibrationValue = 8;      // Для 32 кГц
  141.    
  142.     // Выбор источника для RTC (автоматически)
  143.     PCC_OscInit.RTCClockSelection = PCC_RTC_CLOCK_SOURCE_AUTO;
  144.    
  145.     // Источник тактирования RTC для CPU
  146.     PCC_OscInit.RTCClockCPUSelection = PCC_CPU_RTC_CLOCK_SOURCE_OSC32K;
  147.    
  148.     // Применение конфигурации
  149.     HAL_PCC_Config(&PCC_OscInit);
  150. }
  151.  
  152. /**
  153.  * Timer16_1_Init - инициализация таймера Timer16_1
  154.  * Настройка параметров работы таймера
  155.  */
  156. static void Timer16_1_Init(void)
  157. {
  158.     // Привязка дескриптора к аппаратному таймеру
  159.     htimer16_1.Instance = TIMER16_1;
  160.  
  161.     /* Настройка тактирования таймера */
  162.     htimer16_1.Clock.Source = TIMER16_SOURCE_INTERNAL_SYSTEM;  // От системной шины
  163.     htimer16_1.CountMode = TIMER16_COUNTMODE_INTERNAL;         // Внутренний счет
  164.     htimer16_1.Clock.Prescaler = TIMER16_PRESCALER_1;          // Предделитель 1
  165.     htimer16_1.ActiveEdge = TIMER16_ACTIVEEDGE_RISING;         // Активный фронт
  166.  
  167.     /* Настройка режима обновления регистров ARR и CMP */
  168.     htimer16_1.Preload = TIMER16_PRELOAD_AFTERWRITE;           // Обновление сразу после записи
  169.  
  170.     /* Настройка триггерного режима (для синхронизации с другими таймерами) */
  171.     htimer16_1.Trigger.Source = TIMER16_TRIGGER_TIM0_GPIO0_7;  // Источник триггера
  172.     htimer16_1.Trigger.ActiveEdge = TIMER16_TRIGGER_ACTIVEEDGE_SOFTWARE;  // Программный запуск
  173.     htimer16_1.Trigger.TimeOut = TIMER16_TIMEOUT_DISABLE;      // Таймаут отключен
  174.  
  175.     /* Настройка фильтров входных сигналов */
  176.     htimer16_1.Filter.ExternalClock = TIMER16_FILTER_NONE;     // Фильтр внешнего тактирования отключен
  177.     htimer16_1.Filter.Trigger = TIMER16_FILTER_NONE;           // Фильтр триггера отключен
  178.  
  179.     /* Режим энкодера (не используется) */
  180.     htimer16_1.EncoderMode = TIMER16_ENCODER_DISABLE;          // Режим энкодера отключен
  181.  
  182.     /* Настройка выходного сигнала (Waveform) */
  183.     htimer16_1.Waveform.Enable = TIMER16_WAVEFORM_GENERATION_DISABLE;  // Генерация отключена (будет включена позже)
  184.     htimer16_1.Waveform.Polarity = TIMER16_WAVEFORM_POLARITY_NONINVERTED;  // Прямая полярность
  185.  
  186.     // Инициализация таймера с заданными параметрами
  187.     HAL_Timer16_Init(&htimer16_1);
  188. }
  189.  
  190. void main() {
  191.  
  192.     // Установка адреса обработчика прерываний в регистр mtvec
  193.     write_csr(mtvec, &__TEXT_START__);
  194.  
  195.     // Включение тактирования на шине APB_P для:
  196.     PM->CLK_APB_P_SET =   PM_CLOCK_APB_P_GPIO_0_M      // Порт GPIO_0
  197.                         | PM_CLOCK_APB_P_GPIO_1_M      // Порт GPIO_1
  198.                         | PM_CLOCK_APB_P_GPIO_2_M      // Порт GPIO_2
  199.                         | PM_CLOCK_APB_P_GPIO_IRQ_M;   // Контроллер прерываний GPIO
  200.    
  201.     // Включение тактирования на шине APB_M для:
  202.     PM->CLK_APB_M_SET =   PM_CLOCK_APB_M_PAD_CONFIG_M  // Конфигурация выводов
  203.                         | PM_CLOCK_APB_M_WU_M          // Блок WakeUp
  204.                         | PM_CLOCK_APB_M_PM_M          // Менеджер питания
  205.                         | PM_CLOCK_APB_M_EPIC_M;       // Внешний контроллер прерываний EPIC
  206.    
  207.     // Включение тактирования на шине AHB для SPIFI (Sequential Peripheral Interface)
  208.     PM->CLK_AHB_SET |= PM_CLOCK_AHB_SPIFI_M;
  209.  
  210.     // Настройка системной частоты (требуется для таймера)
  211.     SystemClock_Config(); // Включение тактирования для Timer16_1
  212.  
  213.    
  214.     /**************************Включить вывод Output для Timer16_1**************************/
  215.     /* Port0.10 */
  216.     PAD_CONFIG->PORT_0_CFG |= (PORT_AS_TIMER << (2 * TIMER16_1_OUT));
  217.     /***************************************************************************************/
  218.  
  219.     // Инициализация таймера с настроенными параметрами
  220.     Timer16_1_Init();
  221.  
  222.     // Запуск таймера в непрерывном режиме (счет от 0 до ARR, затем сброс)
  223.     __HAL_TIMER16_START_CONTINUOUS(&htimer16_1);  // Включить непрерывный режим для Timer16_1
  224.  
  225.     // Настройка вывода как выход
  226.     GPIO_0->DIRECTION_OUT =  1<<(9); // зелёный светодиод
  227.     // Установка начального состояния - выключен (0)
  228.     GPIO_0->OUTPUT = (0b0) << (9);
  229.  
  230.     // Настройка вывода как вход
  231.     GPIO_1->DIRECTION_IN =  1<<(15);
  232.  
  233.     // Настройка мультиплексора линий: 7-я линия подключается к порту 1 (Mode=3)
  234.     // Каждая линия использует 4 бита в регистре LINE_MUX
  235.     GPIO_IRQ->LINE_MUX = 3 << (7*4);
  236.    
  237.     // Настройка режима: прерывание по фронту (EDGE), а не по уровню
  238.     GPIO_IRQ->EDGE = 1 << 7;
  239.    
  240.     // Настройка типа фронта: спадающий (1->0) - LEVEL_CLEAR бит установлен
  241.     GPIO_IRQ->LEVEL_CLEAR = 1 << 7;
  242.    
  243.     // Разрешение прерывания на 7-й линии
  244.     GPIO_IRQ->ENABLE_SET = 1 << 7;
  245.  
  246.     // Снятие маски (разрешение) прерывания от GPIO в EPIC
  247.     EPIC->MASK_LEVEL_SET = 1 << EPIC_GPIO_IRQ_INDEX;  // Разрешение прерываний EPIC
  248.  
  249.     // Установка бита MIE (Machine Interrupt Enable) в регистре mstatus
  250.     set_csr(mstatus, MSTATUS_MIE);
  251.    
  252.     // Установка бита MEIE (Machine External Interrupt Enable) в регистре mie
  253.     // Разрешает внешние прерывания
  254.     set_csr(mie, MIE_MEIE);
  255.  
  256.     uint16_t i = 2;          // Переменная цикла для ШИМ
  257.     uint32_t count = 0;      // Для хранения значения счетчика тиков
  258.     uint32_t local_pi = 0;   // Для хранения вычисленного π
  259.  
  260.     while (1)
  261.     {
  262.         for(i = 2; i <= 256; i++)
  263.         {
  264.             // Плавно уменьшаем яркость красного светодиода с помощью ШИМ на Timer16_1
  265.             HAL_Timer16_StartPWM(&htimer16_1, 0xFFFF, 0xFFFF/i); // Генерация волновой формы - ШИМ
  266.            
  267.             if (task == 0){
  268.                 // Задача 1: подсчет тиков
  269.                 count = tick_counter();
  270.             }
  271.             else{
  272.                 // Задача 2: вычисление числа π
  273.                 local_pi = calculate_pi();
  274.             }
  275.         }
  276.        
  277.         for(i = 256; i > 1; i--)
  278.         {  
  279.             // Плавно увеличиваем яркость красного светодиода с помощью ШИМ на Timer16_1
  280.             HAL_Timer16_StartPWM(&htimer16_1, 0xFFFF, 0xFFFF/i);
  281.  
  282.             if (task == 0){
  283.                 count = tick_counter();
  284.             }
  285.             else{
  286.                 local_pi = calculate_pi();
  287.             }
  288.         }
  289.     }
  290. }
  291.  
  292.  
Advertisement
Add Comment
Please, Sign In to add comment