Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // Регистры управления и статуса RISC-V (базовые определения)
- #include "riscv_csr_encoding.h"
- // Специфичные для ядра SCR1 определения CSR
- #include "scr1_csr_encoding.h"
- // Карта памяти микроконтроллера (адреса периферии)
- #include "mcu32_memory_map.h"
- // Менеджер питания и тактирования
- #include <power_manager.h>
- // Конфигурация выводов (мультиплексирование функций)
- #include "pad_config.h"
- // Прерывания от GPIO
- #include <gpio_irq.h>
- // Внешний контроллер прерываний (EPIC)
- #include <epic.h>
- // Утилиты для работы с CSR регистрами
- #include <csr.h>
- // Драйвер GPIO
- #include <gpio.h>
- // Стандартные целочисленные типы
- #include <stdint.h>
- // Стандартная библиотека (rand, RAND_MAX)
- #include <stdlib.h>
- // HAL для 16-битного таймера
- #include "mik32_hal_timer16.h"
- // HAL для контроля тактирования
- #include "mik32_hal_pcc.h"
- // HAL для ЦАП (не используется в коде, но подключен)
- #include "mik32_hal_dac.h"
- // Указатель на структуру GPIO для порта 0 (используется базовый адрес из карты памяти)
- #define GPIO_X ((GPIO_TypeDef*)GPIO_0_BASE_ADDRESS )
- // Внешняя переменная, определяемая компоновщиком - содержит адрес начала кода программы
- // Используется для установки вектора прерываний
- extern unsigned long __TEXT_START__;
- // Флаг переключения между двумя задачами в основном цикле
- // Изменяется в обработчике прерывания при нажатии кнопки
- int task = 0;
- // Обработчик прерывания
- void trap_handler() {
- if ( EPIC->RAW_STATUS & (1<<EPIC_GPIO_IRQ_INDEX)) // Проверка источника прерывания (прерывание пришло от GPIO?)
- {
- GPIO_0->OUTPUT ^= (0b1)<<(9); // зажигаем зеленый светодиод
- task = ~task;
- GPIO_IRQ->CLEAR = (1 << 7); // Сброс флага прерывания GPIO
- EPIC->CLEAR = (1<<EPIC_GPIO_IRQ_INDEX); // Сброс флага прерывания порта ввода-вывода
- }
- }
- #define CRC32_POLY 0xEDB88320
- // Таблица предвычисленных значений для CRC32
- uint32_t crc32_table[256];
- // Счетчик тиков (количество вызовов функции tick_counter)
- uint32_t counts_of_tick;
- // Переменные для вычисления числа π методом Монте-Карло
- uint32_t iterations = 1; // Количество итераций
- uint32_t inside = 1; // Количество точек, попавших внутрь круга
- uint32_t pi = 0; // Вычисленное значение π
- // ============================================================================
- // ФУНКЦИИ ДЛЯ ВЫЧИСЛЕНИЙ
- // ============================================================================
- /**
- * calculate_pi - вычисление числа π методом Монте-Карло
- *
- * Метод: генерируются случайные точки с координатами (x,y) в квадрате [0,1]x[0,1]
- * Подсчитывается количество точек, попавших в круг радиусом 1 (x^2 + y^2 <= 1)
- * π ≈ 4 * (точек_в_круге / всего_точек)
- *
- * @return long - текущее приближение π (целое число, что некорректно)
- */
- long calculate_pi(){
- // Генерация случайных координат в диапазоне [0, 1]
- float x = (float)rand() / RAND_MAX;
- float y = (float)rand() / RAND_MAX;
- // Проверка попадания точки в круг
- if ((x*x+y*y) <= 1.0f) inside++;
- // Вычисление приближения π
- pi = 4.0f * inside / iterations;
- // Увеличение счетчика итераций
- iterations++;
- return pi; // Возврат целого числа (должен быть float/double)
- }
- /**
- * tick_counter - простой счетчик вызовов
- * Увеличивает глобальный счетчик и возвращает его значение
- *
- * @return uint32_t - текущее значение счетчика
- */
- uint32_t tick_counter() {
- counts_of_tick++;
- return counts_of_tick;
- }
- // ============================================================================
- // НАСТРОЙКА ТАЙМЕРА
- // ============================================================================
- // Дескриптор таймера Timer16_1 (структура с настройками)
- Timer16_HandleTypeDef htimer16_1;
- /**
- * SystemClock_Config - настройка системной частоты
- * Использует HAL для конфигурации генераторов и делителей
- */
- void SystemClock_Config(void)
- {
- PCC_InitTypeDef PCC_OscInit = {0};
- // Включение всех генераторов
- PCC_OscInit.OscillatorEnable = PCC_OSCILLATORTYPE_ALL;
- // Выбор основного системного генератора - 32 МГц
- PCC_OscInit.FreqMon.OscillatorSystem = PCC_OSCILLATORTYPE_OSC32M;
- // Не фиксировать принудительно системный генератор
- PCC_OscInit.FreqMon.ForceOscSys = PCC_FORCE_OSC_SYS_UNFIXED;
- // Источник 32 кГц - внешний или внутренний OSC32K
- PCC_OscInit.FreqMon.Force32KClk = PCC_FREQ_MONITOR_SOURCE_OSC32K;
- // Делители шин (0 = деление на 1)
- PCC_OscInit.AHBDivider = 0; // AHB шина
- PCC_OscInit.APBMDivider = 0; // APB M шина (периферия)
- PCC_OscInit.APBPDivider = 0; // APB P шина (периферия)
- // Калибровочные значения для внутренних генераторов
- PCC_OscInit.HSI32MCalibrationValue = 128; // Для 32 МГц
- PCC_OscInit.LSI32KCalibrationValue = 8; // Для 32 кГц
- // Выбор источника для RTC (автоматически)
- PCC_OscInit.RTCClockSelection = PCC_RTC_CLOCK_SOURCE_AUTO;
- // Источник тактирования RTC для CPU
- PCC_OscInit.RTCClockCPUSelection = PCC_CPU_RTC_CLOCK_SOURCE_OSC32K;
- // Применение конфигурации
- HAL_PCC_Config(&PCC_OscInit);
- }
- /**
- * Timer16_1_Init - инициализация таймера Timer16_1
- * Настройка параметров работы таймера
- */
- static void Timer16_1_Init(void)
- {
- // Привязка дескриптора к аппаратному таймеру
- htimer16_1.Instance = TIMER16_1;
- /* Настройка тактирования таймера */
- htimer16_1.Clock.Source = TIMER16_SOURCE_INTERNAL_SYSTEM; // От системной шины
- htimer16_1.CountMode = TIMER16_COUNTMODE_INTERNAL; // Внутренний счет
- htimer16_1.Clock.Prescaler = TIMER16_PRESCALER_1; // Предделитель 1
- htimer16_1.ActiveEdge = TIMER16_ACTIVEEDGE_RISING; // Активный фронт
- /* Настройка режима обновления регистров ARR и CMP */
- htimer16_1.Preload = TIMER16_PRELOAD_AFTERWRITE; // Обновление сразу после записи
- /* Настройка триггерного режима (для синхронизации с другими таймерами) */
- htimer16_1.Trigger.Source = TIMER16_TRIGGER_TIM0_GPIO0_7; // Источник триггера
- htimer16_1.Trigger.ActiveEdge = TIMER16_TRIGGER_ACTIVEEDGE_SOFTWARE; // Программный запуск
- htimer16_1.Trigger.TimeOut = TIMER16_TIMEOUT_DISABLE; // Таймаут отключен
- /* Настройка фильтров входных сигналов */
- htimer16_1.Filter.ExternalClock = TIMER16_FILTER_NONE; // Фильтр внешнего тактирования отключен
- htimer16_1.Filter.Trigger = TIMER16_FILTER_NONE; // Фильтр триггера отключен
- /* Режим энкодера (не используется) */
- htimer16_1.EncoderMode = TIMER16_ENCODER_DISABLE; // Режим энкодера отключен
- /* Настройка выходного сигнала (Waveform) */
- htimer16_1.Waveform.Enable = TIMER16_WAVEFORM_GENERATION_DISABLE; // Генерация отключена (будет включена позже)
- htimer16_1.Waveform.Polarity = TIMER16_WAVEFORM_POLARITY_NONINVERTED; // Прямая полярность
- // Инициализация таймера с заданными параметрами
- HAL_Timer16_Init(&htimer16_1);
- }
- void main() {
- // Установка адреса обработчика прерываний в регистр mtvec
- write_csr(mtvec, &__TEXT_START__);
- // Включение тактирования на шине APB_P для:
- PM->CLK_APB_P_SET = PM_CLOCK_APB_P_GPIO_0_M // Порт GPIO_0
- | PM_CLOCK_APB_P_GPIO_1_M // Порт GPIO_1
- | PM_CLOCK_APB_P_GPIO_2_M // Порт GPIO_2
- | PM_CLOCK_APB_P_GPIO_IRQ_M; // Контроллер прерываний GPIO
- // Включение тактирования на шине APB_M для:
- PM->CLK_APB_M_SET = PM_CLOCK_APB_M_PAD_CONFIG_M // Конфигурация выводов
- | PM_CLOCK_APB_M_WU_M // Блок WakeUp
- | PM_CLOCK_APB_M_PM_M // Менеджер питания
- | PM_CLOCK_APB_M_EPIC_M; // Внешний контроллер прерываний EPIC
- // Включение тактирования на шине AHB для SPIFI (Sequential Peripheral Interface)
- PM->CLK_AHB_SET |= PM_CLOCK_AHB_SPIFI_M;
- // Настройка системной частоты (требуется для таймера)
- SystemClock_Config(); // Включение тактирования для Timer16_1
- /**************************Включить вывод Output для Timer16_1**************************/
- /* Port0.10 */
- PAD_CONFIG->PORT_0_CFG |= (PORT_AS_TIMER << (2 * TIMER16_1_OUT));
- /***************************************************************************************/
- // Инициализация таймера с настроенными параметрами
- Timer16_1_Init();
- // Запуск таймера в непрерывном режиме (счет от 0 до ARR, затем сброс)
- __HAL_TIMER16_START_CONTINUOUS(&htimer16_1); // Включить непрерывный режим для Timer16_1
- // Настройка вывода как выход
- GPIO_0->DIRECTION_OUT = 1<<(9); // зелёный светодиод
- // Установка начального состояния - выключен (0)
- GPIO_0->OUTPUT = (0b0) << (9);
- // Настройка вывода как вход
- GPIO_1->DIRECTION_IN = 1<<(15);
- // Настройка мультиплексора линий: 7-я линия подключается к порту 1 (Mode=3)
- // Каждая линия использует 4 бита в регистре LINE_MUX
- GPIO_IRQ->LINE_MUX = 3 << (7*4);
- // Настройка режима: прерывание по фронту (EDGE), а не по уровню
- GPIO_IRQ->EDGE = 1 << 7;
- // Настройка типа фронта: спадающий (1->0) - LEVEL_CLEAR бит установлен
- GPIO_IRQ->LEVEL_CLEAR = 1 << 7;
- // Разрешение прерывания на 7-й линии
- GPIO_IRQ->ENABLE_SET = 1 << 7;
- // Снятие маски (разрешение) прерывания от GPIO в EPIC
- EPIC->MASK_LEVEL_SET = 1 << EPIC_GPIO_IRQ_INDEX; // Разрешение прерываний EPIC
- // Установка бита MIE (Machine Interrupt Enable) в регистре mstatus
- set_csr(mstatus, MSTATUS_MIE);
- // Установка бита MEIE (Machine External Interrupt Enable) в регистре mie
- // Разрешает внешние прерывания
- set_csr(mie, MIE_MEIE);
- uint16_t i = 2; // Переменная цикла для ШИМ
- uint32_t count = 0; // Для хранения значения счетчика тиков
- uint32_t local_pi = 0; // Для хранения вычисленного π
- while (1)
- {
- for(i = 2; i <= 256; i++)
- {
- // Плавно уменьшаем яркость красного светодиода с помощью ШИМ на Timer16_1
- HAL_Timer16_StartPWM(&htimer16_1, 0xFFFF, 0xFFFF/i); // Генерация волновой формы - ШИМ
- if (task == 0){
- // Задача 1: подсчет тиков
- count = tick_counter();
- }
- else{
- // Задача 2: вычисление числа π
- local_pi = calculate_pi();
- }
- }
- for(i = 256; i > 1; i--)
- {
- // Плавно увеличиваем яркость красного светодиода с помощью ШИМ на Timer16_1
- HAL_Timer16_StartPWM(&htimer16_1, 0xFFFF, 0xFFFF/i);
- if (task == 0){
- count = tick_counter();
- }
- else{
- local_pi = calculate_pi();
- }
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment