├── 01_Minimal ├── .cproject ├── .project ├── 01_Minimal Debug.launch └── Src │ ├── gpio.c │ ├── main.c │ ├── stm32f4.ld │ ├── stm32g431.h │ ├── system_init.c │ └── vectors.c ├── 02_HSE ├── .cproject ├── .project ├── 02_HSE Debug.launch └── Src │ ├── gpio.c │ ├── main.c │ ├── stm32f4.ld │ ├── stm32g431.h │ ├── system_init.c │ └── vectors.c ├── 03_TIM2 ├── .cproject ├── .project ├── 03_TIM2.launch └── Src │ ├── gpio.c │ ├── main.c │ ├── stm32f4.ld │ ├── stm32g431.h │ ├── system_init.c │ ├── tim2.c │ └── vectors.c ├── 04_TIM2_DAC ├── .cproject ├── .project ├── 04_TIM2_DAC Debug.launch └── Src │ ├── dac.c │ ├── gpio.c │ ├── main.c │ ├── stm32f4.ld │ ├── stm32g431.h │ ├── system_init.c │ ├── tim2.c │ └── vectors.c ├── 05_TIM2_DAC_SIN ├── .cproject ├── .project ├── 05_TIM2_DAC_SIN.launch └── Src │ ├── dac.c │ ├── gpio.c │ ├── main.c │ ├── stm32f4.ld │ ├── stm32g431.h │ ├── system_init.c │ ├── tim2.c │ └── vectors.c ├── 06_ADC_DAC ├── .cproject ├── .project ├── 06_ADC_DAC.launch └── Src │ ├── adc.c │ ├── dac.c │ ├── gpio.c │ ├── main.c │ ├── stm32f4.ld │ ├── stm32g431.h │ ├── system_init.c │ ├── tim2.c │ └── vectors.c ├── 07_ADC_DAC_FIL ├── .cproject ├── .project ├── 07_ADC_DAC_FIL.launch └── Src │ ├── adc.c │ ├── dac.c │ ├── gpio.c │ ├── main.c │ ├── stm32f4.ld │ ├── stm32g431.h │ ├── system_init.c │ ├── tim2.c │ └── vectors.c ├── 08_ADC_DAC_FIL_DET ├── .cproject ├── .project ├── 08_ADC_DAC_FIL_DET.launch └── Src │ ├── adc.c │ ├── dac.c │ ├── gpio.c │ ├── main.c │ ├── stm32f4.ld │ ├── stm32g431.h │ ├── system_init.c │ ├── tim2.c │ └── vectors.c ├── 09_ADC_DAC_DET_FIL_DET_EN ├── .cproject ├── .project ├── 09_ADC_DAC_DET_FIL_DET_EN.launch └── Src │ ├── adc.c │ ├── dac.c │ ├── encoder.c │ ├── gpio.c │ ├── main.c │ ├── stm32f4.ld │ ├── stm32g431.h │ ├── system_init.c │ ├── tim2.c │ └── vectors.c ├── 10_ADC_DAC_DET_FIL_DET_EN_OLED ├── .cproject ├── .project ├── 10_ADC_DAC_DET_FIL_DET_EN_OLED.launch └── Src │ ├── adc.c │ ├── dac.c │ ├── encoder.c │ ├── gpio.c │ ├── main.c │ ├── oled.c │ ├── oledfont.h │ ├── stm32f4.ld │ ├── stm32g431.h │ ├── system_init.c │ ├── tim2.c │ └── vectors.c ├── 11_SIMPLE_RADIO ├── .cproject ├── .project ├── 11_SIMPLE_RADIO.launch └── Src │ ├── adc.c │ ├── dac.c │ ├── encoder.c │ ├── gpio.c │ ├── main.c │ ├── oled.c │ ├── oledfont.h │ ├── stm32f4.ld │ ├── stm32g431.h │ ├── system_init.c │ └── vectors.c ├── 12_SIMPLE_RADIO_DMA ├── .cproject ├── .project ├── 12_SIMPLE_RADIO_DMA Debug.launch └── Src │ ├── adc.c │ ├── dac.c │ ├── encoder.c │ ├── gpio.c │ ├── main.c │ ├── oled.c │ ├── oledfont.h │ ├── stm32f4.ld │ ├── stm32g431.h │ ├── system_init.c │ └── vectors.c ├── 13_SIMPLE_RADIO_DMA_ASM ├── .cproject ├── .project ├── 13_SIMPLE_RADIO_DMA_ASM Debug.launch ├── Src │ ├── adc.c │ ├── dac.c │ ├── dsp.s │ ├── encoder.c │ ├── gpio.c │ ├── main.c │ ├── oled.c │ ├── oledfont.h │ ├── stm32f4.ld │ ├── stm32g431.h │ ├── system_init.c │ └── vectors.c └── Коррекция шкалы F I.xlsx ├── 14_SIMPLE_RADIO_DMA_ASM_II ├── .cproject ├── .project ├── 14_SIMPLE_RADIO_DMA_ASM_II.launch ├── Src │ ├── adc.c │ ├── dac.c │ ├── dsp.s │ ├── encoder.c │ ├── gpio.c │ ├── level.c │ ├── main.c │ ├── oled.c │ ├── oledfont.h │ ├── stm32f4.ld │ ├── stm32g431.h │ ├── system_init.c │ └── vectors.c └── Коррекция шкалы F II.xlsx ├── README.md └── Простой цифровой радиоприемник V3.pdf /01_Minimal/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | 01_Minimal 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.cdt.managedbuilder.core.genmakebuilder 10 | clean,full,incremental, 11 | 12 | 13 | 14 | 15 | org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder 16 | full,incremental, 17 | 18 | 19 | 20 | 21 | 22 | com.st.stm32cube.ide.mcu.MCUProjectNature 23 | org.eclipse.cdt.core.cnature 24 | com.st.stm32cube.ide.mcu.MCUCubeIdeServicesRevAev2ProjectNature 25 | com.st.stm32cube.ide.mcu.MCUManagedMakefileProjectNature 26 | com.st.stm32cube.ide.mcu.MCUSingleCpuProjectNature 27 | com.st.stm32cube.ide.mcu.MCURootProjectNature 28 | org.eclipse.cdt.managedbuilder.core.managedBuildNature 29 | org.eclipse.cdt.managedbuilder.core.ScannerConfigNature 30 | 31 | 32 | -------------------------------------------------------------------------------- /01_Minimal/Src/gpio.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | void GpioInit(void) 5 | { 6 | SET_BIT(RCC_AHB2ENR, RCC_AHB2ENR_GPIOBEN); // Подать тактовый сигнал на модуль GPIOB 7 | MODIFY_REG(GPIOB_MODER, GPIO_MODER_MODE8, 1< 2 | 3 | void GpioInit(void); 4 | 5 | int main(void) 6 | { 7 | 8 | GpioInit(); //Настройка линий PB7 и PB8 на вывод 9 | 10 | while(1) 11 | { 12 | uint32_t i=1000000; //Количество итераций в цикле задержки 13 | while(i)i--; //Задержка 14 | INVERT_BIT(GPIOB_ODR, GPIO_ODR_OD8); //Инвертировать LD2 (PB8) 15 | INVERT_BIT(GPIOB_ODR, GPIO_ODR_OD7); //Инвертировать (PB7) 16 | } 17 | } 18 | 19 | 20 | -------------------------------------------------------------------------------- /01_Minimal/Src/stm32f4.ld: -------------------------------------------------------------------------------- 1 | /* Точка входа - функция sturt_up */ 2 | ENTRY(start_up) 3 | 4 | /* 5 | Начальные адреса и размер RAM и FLASH 6 | FLASH также аппаратно отображается в адреса 0x00000000 - 0x00020000 7 | */ 8 | 9 | MEMORY 10 | { 11 | RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 32K 12 | FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 128K 13 | } 14 | 15 | /* Размер таблицы векторов прерывания */ 16 | _size_vector_table = 0x0400; 17 | 18 | /* 19 | Вершина стека 20 | Находится в конце RAM 21 | */ 22 | _estack = ORIGIN(RAM) + LENGTH(RAM); 23 | 24 | 25 | SECTIONS { 26 | 27 | /* Секция векторов прерывания */ 28 | .vectors : { 29 | . = ALIGN(4); 30 | _svector = .; 31 | /*ключевое слово KEEP сохраняет раздел даже если на него нет ссылок*/ 32 | KEEP(*(.vectors)); 33 | . = _svector + _size_vector_table; 34 | . = ALIGN(4); 35 | _evector = .; 36 | } > FLASH 37 | 38 | /* Секция кода программы и констант*/ 39 | .text : { 40 | *(.text*) 41 | *(.rodata*) 42 | } > FLASH 43 | 44 | /* Секция глобальных переменных, инициализированных нулем */ 45 | .bss : { 46 | _sbss = .; 47 | *(.bss*) 48 | *(COMMON) 49 | . = ALIGN(4); 50 | _ebss = .; 51 | } > RAM 52 | 53 | /* Секция глобальных переменных, инициализированных константами */ 54 | .data : { 55 | _sdata_ram = .; 56 | *(.data*) 57 | . = ALIGN(4); 58 | _edata_ram = .; 59 | } > RAM AT > FLASH 60 | 61 | } 62 | 63 | /* Начальный и конечный адрес секции .data во flash памяти */ 64 | _sdata_flash = LOADADDR(.data); 65 | _edata_flash = _sdata_flash + SIZEOF(.data); 66 | 67 | 68 | -------------------------------------------------------------------------------- /01_Minimal/Src/stm32g431.h: -------------------------------------------------------------------------------- 1 | #ifndef __STM32G431_H 2 | #define __STM32G431_H 3 | 4 | //Определение типов данных, принятых в embedded программировании 5 | typedef unsigned int uint32_t; 6 | typedef unsigned short uint16_t; 7 | typedef unsigned char uint8_t ; 8 | typedef int int32_t ; 9 | 10 | //Макросы, упрощающие работу с регистрами, где 11 | //REG - адрес регистра 12 | //BIT - 32 битное слово - биты для которых будет выполнена данная функция. 13 | //Например: INVERT(GPIOB_ODR,0x6) проинвертирует биты 1 и 2 в регистре GPIOB_ODR 14 | 15 | #define SET_BIT(REG, BIT) ((REG) |= (BIT)) 16 | #define CLEAR_BIT(REG, BIT) ((REG) &= ~(BIT)) 17 | #define INVERT_BIT(REG, BIT) ((REG) ^= (BIT)) 18 | #define READ_BIT(REG, BIT) ((REG) & (BIT)) 19 | #define CLEAR_REG(REG) ((REG) = (0x0)) 20 | #define READ_REG(REG) ((REG)) 21 | 22 | //Макрос WRITE_REG выполняет запись 32 битного слова в регистр, где 23 | //REG - адрес регистра 24 | //VAL - значение 25 | #define WRITE_REG(REG, VAL) ((REG) = (VAL)) 26 | 27 | //Макрос MODIFY_REG выполняет модификацию поля в регистре, где 28 | //REG - адрес регистра 29 | //CLEARMASK - 32 битное слово, биты для которых будет выполнена операция сброса в 0 30 | //SETMASK - 32 битное слово, биты для которых будет выполнена операция установки в 1 31 | //Например: MODIFY_REG(GPIOB_MODER, 0x00030000, 0x00010000) - сбрасывает биты 16 и 17 в 0, 32 | //и устанавливает бит 16 в 1. 33 | 34 | #define MODIFY_REG(REG, CLEARMASK, SETMASK) WRITE_REG((REG), (((READ_REG(REG)) & (~(CLEARMASK))) | (SETMASK))) 35 | 36 | /*********************** RCC (Reset and clock control) *********************************/ 37 | #define RCC_BASE (0x40021000) 38 | #define RCC_AHB2ENR (*(volatile uint32_t *) (RCC_BASE + 0x4c)) 39 | 40 | #define RCC_AHB2ENR_GPIOBEN_Pos (1U) 41 | #define RCC_AHB2ENR_GPIOBEN 0x00000002 42 | 43 | /*********************** GPIO (General-purpose I/Os) *********************************/ 44 | #define GPIOB_BASE (0x48000400) 45 | #define GPIOB_MODER (*(volatile uint32_t *) (GPIOB_BASE + 0x00)) 46 | #define GPIOB_ODR (*(volatile uint32_t *) (GPIOB_BASE + 0x14)) 47 | 48 | //Bits definition for GPIO_MODER register 49 | #define GPIO_MODER_MODE0_Pos (0U) 50 | #define GPIO_MODER_MODE0 0x00000003 51 | #define GPIO_MODER_MODE1_Pos (2U) 52 | #define GPIO_MODER_MODE1 0x0000000C 53 | #define GPIO_MODER_MODE2_Pos (4U) 54 | #define GPIO_MODER_MODE2 0x00000030 55 | #define GPIO_MODER_MODE3_Pos (6U) 56 | #define GPIO_MODER_MODE3 0x000000C0 57 | #define GPIO_MODER_MODE4_Pos (8U) 58 | #define GPIO_MODER_MODE4 0x00000300 59 | #define GPIO_MODER_MODE5_Pos (10U) 60 | #define GPIO_MODER_MODE5 0x00000C00 61 | #define GPIO_MODER_MODE6_Pos (12U) 62 | #define GPIO_MODER_MODE6 0x00003000 63 | #define GPIO_MODER_MODE7_Pos (14U) 64 | #define GPIO_MODER_MODE7 0x0000C000 65 | #define GPIO_MODER_MODE8_Pos (16U) 66 | #define GPIO_MODER_MODE8 0x00030000 67 | #define GPIO_MODER_MODE9_Pos (18U) 68 | #define GPIO_MODER_MODE9 0x000C0000 69 | #define GPIO_MODER_MODE10_Pos (20U) 70 | #define GPIO_MODER_MODE10 0x00300000 71 | #define GPIO_MODER_MODE11_Pos (22U) 72 | #define GPIO_MODER_MODE11 0x00C00000 73 | #define GPIO_MODER_MODE12_Pos (24U) 74 | #define GPIO_MODER_MODE12 0x03000000 75 | #define GPIO_MODER_MODE13_Pos (26U) 76 | #define GPIO_MODER_MODE13 0x0C000000 77 | #define GPIO_MODER_MODE14_Pos (28U) 78 | #define GPIO_MODER_MODE14 0x30000000 79 | #define GPIO_MODER_MODE15_Pos (30U) 80 | #define GPIO_MODER_MODE15 0xC0000000 81 | 82 | //Bits definition for GPIO_ODR register 83 | 84 | #define GPIO_ODR_OD0_Pos (0U) 85 | #define GPIO_ODR_OD0 0x00000001 86 | #define GPIO_ODR_OD1_Pos (1U) 87 | #define GPIO_ODR_OD1 0x00000002 88 | #define GPIO_ODR_OD2_Pos (2U) 89 | #define GPIO_ODR_OD2 0x00000004 90 | #define GPIO_ODR_OD3_Pos (3U) 91 | #define GPIO_ODR_OD3 0x00000008 92 | #define GPIO_ODR_OD4_Pos (4U) 93 | #define GPIO_ODR_OD4 0x00000010 94 | #define GPIO_ODR_OD5_Pos (5U) 95 | #define GPIO_ODR_OD5 0x00000020 96 | #define GPIO_ODR_OD6_Pos (6U) 97 | #define GPIO_ODR_OD6 0x00000040 98 | #define GPIO_ODR_OD7_Pos (7U) 99 | #define GPIO_ODR_OD7 0x00000080 100 | #define GPIO_ODR_OD8_Pos (8U) 101 | #define GPIO_ODR_OD8 0x00000100 102 | #define GPIO_ODR_OD9_Pos (9U) 103 | #define GPIO_ODR_OD9 0x00000200 104 | #define GPIO_ODR_OD10_Pos (10U) 105 | #define GPIO_ODR_OD10 0x00000400 106 | #define GPIO_ODR_OD11_Pos (11U) 107 | #define GPIO_ODR_OD11 0x00000800 108 | #define GPIO_ODR_OD12_Pos (12U) 109 | #define GPIO_ODR_OD12 0x00001000 110 | #define GPIO_ODR_OD13_Pos (13U) 111 | #define GPIO_ODR_OD13 0x00002000 112 | #define GPIO_ODR_OD14_Pos (14U) 113 | #define GPIO_ODR_OD14 0x00004000 114 | #define GPIO_ODR_OD15_Pos (15U) 115 | #define GPIO_ODR_OD15 0x00008000 116 | 117 | 118 | #endif /* __STM32G431_H */ 119 | 120 | -------------------------------------------------------------------------------- /01_Minimal/Src/system_init.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* Константы определены в файле stm32f4.ld */ 4 | extern uint32_t _estack; 5 | extern uint32_t _sdata_ram, _edata_ram; 6 | extern uint32_t _sbss, _ebss; 7 | extern uint32_t _svector, _evector; 8 | extern uint32_t _sdata_flash, _edata_flash; 9 | 10 | int main(void); 11 | 12 | /* Точка входа */ 13 | void start_up(void) 14 | { 15 | uint32_t *src, *dst; 16 | 17 | /* Копирование данных секции .data из FLASH в RAM */ 18 | src = &_sdata_flash; 19 | dst = &_sdata_ram; 20 | while (dst < &_edata_ram) { 21 | *dst++ = *src++; 22 | } 23 | 24 | /* Запись нулей в область памяти секции .bss */ 25 | dst = &_sbss; 26 | while (dst < &_ebss) { 27 | *dst++ = 0; 28 | } 29 | 30 | main(); 31 | } 32 | 33 | 34 | -------------------------------------------------------------------------------- /01_Minimal/Src/vectors.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void start_up(void); 4 | void nmi_handler(void); 5 | void hardfault_handler(void); 6 | 7 | extern uint32_t _estack; 8 | 9 | /* Таблица векторов прерывания */ 10 | 11 | __attribute__ ((section(".vectors"),used))//Таблицу размещаем в секции .vectors 12 | uint32_t * vectors[] = { 13 | (uint32_t *) &_estack, //Вершина стека 14 | (uint32_t *) start_up, //Обработчик reset (точка входа) 15 | (uint32_t *) nmi_handler, //Обработчик немаскируемого прерывания 16 | (uint32_t *) hardfault_handler //Обработчик прерывания аппаратной ошибки 17 | }; 18 | 19 | 20 | /* Обработчик немаскируемого прерывания */ 21 | void nmi_handler(void) 22 | { 23 | for (;;); 24 | } 25 | 26 | /* Обработчик прерывания аппаратной ошибки */ 27 | void hardfault_handler(void) 28 | { 29 | for (;;); 30 | } 31 | -------------------------------------------------------------------------------- /02_HSE/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | 02_HSE 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.cdt.managedbuilder.core.genmakebuilder 10 | clean,full,incremental, 11 | 12 | 13 | 14 | 15 | org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder 16 | full,incremental, 17 | 18 | 19 | 20 | 21 | 22 | com.st.stm32cube.ide.mcu.MCUProjectNature 23 | org.eclipse.cdt.core.cnature 24 | com.st.stm32cube.ide.mcu.MCUCubeIdeServicesRevAev2ProjectNature 25 | com.st.stm32cube.ide.mcu.MCUManagedMakefileProjectNature 26 | com.st.stm32cube.ide.mcu.MCUSingleCpuProjectNature 27 | com.st.stm32cube.ide.mcu.MCURootProjectNature 28 | org.eclipse.cdt.managedbuilder.core.managedBuildNature 29 | org.eclipse.cdt.managedbuilder.core.ScannerConfigNature 30 | 31 | 32 | -------------------------------------------------------------------------------- /02_HSE/02_HSE Debug.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /02_HSE/Src/gpio.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | void GpioInit(void) 5 | { 6 | SET_BIT(RCC_AHB2ENR, RCC_AHB2ENR_GPIOBEN); // Подать тактовый сигнал на модуль GPIOB 7 | MODIFY_REG(GPIOB_MODER, GPIO_MODER_MODE8, 1< 2 | 3 | void GpioInit(void); 4 | 5 | int main(void) 6 | { 7 | 8 | GpioInit(); //Настройка линий PB7 и PB8 на вывод 9 | 10 | while(1) 11 | { 12 | uint32_t i=1000000; //Количество итераций в цикле задержки 13 | while(i)i--; //Задержка 14 | INVERT_BIT(GPIOB_ODR, GPIO_ODR_OD8); //Инвертировать LD2 (PB8) 15 | INVERT_BIT(GPIOB_ODR, GPIO_ODR_OD7); //Инвертировать (PB7) 16 | } 17 | } 18 | 19 | 20 | -------------------------------------------------------------------------------- /02_HSE/Src/stm32f4.ld: -------------------------------------------------------------------------------- 1 | /* Точка входа - функция sturt_up */ 2 | ENTRY(start_up) 3 | 4 | /* 5 | Начальные адреса и размер RAM и FLASH 6 | FLASH также аппаратно отображается в адреса 0x00000000 - 0x00020000 7 | */ 8 | 9 | MEMORY 10 | { 11 | RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 32K 12 | FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 128K 13 | } 14 | 15 | /* Размер таблицы векторов прерывания */ 16 | _size_vector_table = 0x0400; 17 | 18 | /* 19 | Вершина стека 20 | Находится в конце RAM 21 | */ 22 | _estack = ORIGIN(RAM) + LENGTH(RAM); 23 | 24 | 25 | SECTIONS { 26 | 27 | /* Секция векторов прерывания */ 28 | .vectors : { 29 | . = ALIGN(4); 30 | _svector = .; 31 | /*ключевое слово KEEP сохраняет раздел даже если на него нет ссылок*/ 32 | KEEP(*(.vectors)); 33 | . = _svector + _size_vector_table; 34 | . = ALIGN(4); 35 | _evector = .; 36 | } > FLASH 37 | 38 | /* Секция кода программы и констант*/ 39 | .text : { 40 | *(.text*) 41 | *(.rodata*) 42 | } > FLASH 43 | 44 | /* Секция глобальных переменных, инициализированных нулем */ 45 | .bss : { 46 | _sbss = .; 47 | *(.bss*) 48 | *(COMMON) 49 | . = ALIGN(4); 50 | _ebss = .; 51 | } > RAM 52 | 53 | /* Секция глобальных переменных, инициализированных константами */ 54 | .data : { 55 | _sdata_ram = .; 56 | *(.data*) 57 | . = ALIGN(4); 58 | _edata_ram = .; 59 | } > RAM AT > FLASH 60 | 61 | } 62 | 63 | /* Начальный и конечный адрес секции .data во flash памяти */ 64 | _sdata_flash = LOADADDR(.data); 65 | _edata_flash = _sdata_flash + SIZEOF(.data); 66 | 67 | 68 | -------------------------------------------------------------------------------- /02_HSE/Src/system_init.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* Константы определены в файле stm32f4.ld */ 4 | extern uint32_t _estack; 5 | extern uint32_t _sdata_ram, _edata_ram; 6 | extern uint32_t _sbss, _ebss; 7 | extern uint32_t _svector, _evector; 8 | extern uint32_t _sdata_flash, _edata_flash; 9 | 10 | int main(void); 11 | void SystemClock_Config(void); 12 | 13 | /* Точка входа */ 14 | void start_up(void) 15 | { 16 | uint32_t *src, *dst; 17 | 18 | /* Копирование данных секции .data из FLASH в RAM */ 19 | src = &_sdata_flash; 20 | dst = &_sdata_ram; 21 | while (dst < &_edata_ram) { 22 | *dst++ = *src++; 23 | } 24 | 25 | /* Запись нулей в область памяти секции .bss */ 26 | dst = &_sbss; 27 | while (dst < &_ebss) { 28 | *dst++ = 0; 29 | } 30 | 31 | SystemClock_Config(); 32 | 33 | main(); 34 | } 35 | 36 | 37 | void SystemClock_Config(void) 38 | { 39 | 40 | //Включить режим повышения выходного напряжения главного регулятора до 1,28 вольт 41 | CLEAR_BIT(PWR_CR5, PWR_CR5_R1MODE); 42 | 43 | //Установка задержки чтения FLASH памяти до 4-х тактов 44 | FLASH_ACR=FLASH_ACR_DBG_SWEN | FLASH_ACR_DCEN | FLASH_ACR_ICEN | FLASH_ACR_LATENCY_4WS ; 45 | while((FLASH_ACR & 0xf) != FLASH_ACR_LATENCY_4WS ); 46 | 47 | //Подключение внешнего кварцевого резонатора (HSE ON) 48 | SET_BIT(RCC_CR, RCC_CR_HSEON); 49 | while(READ_BIT(RCC_CR, RCC_CR_HSERDY) != (RCC_CR_HSERDY)); 50 | 51 | //Настройка PLL, используемого для SYSCLK домена 52 | //PLLM=6 (значение поля 5), PLLN=85 (значение поля 85), PLLR=2 (значение поля 0) 53 | MODIFY_REG(RCC_PLLCFGR, RCC_PLLCFGR_PLLSRC | RCC_PLLCFGR_PLLM | RCC_PLLCFGR_PLLN | RCC_PLLCFGR_PLLR, 54 | RCC_PLLCFGR_PLLSRC_HSE | 5 < 2 | 3 | void start_up(void); 4 | void nmi_handler(void); 5 | void hardfault_handler(void); 6 | 7 | extern uint32_t _estack; 8 | 9 | /* Таблица векторов прерывания */ 10 | 11 | __attribute__ ((section(".vectors"),used))//Таблицу размещаем в секции .vectors 12 | uint32_t * vectors[] = { 13 | (uint32_t *) &_estack, //Вершина стека 14 | (uint32_t *) start_up, //Обработчик reset (точка входа) 15 | (uint32_t *) nmi_handler, //Обработчик немаскируемого прерывания 16 | (uint32_t *) hardfault_handler //Обработчик прерывания аппаратной ошибки 17 | }; 18 | 19 | 20 | /* Обработчик немаскируемого прерывания */ 21 | void nmi_handler(void) 22 | { 23 | for (;;); 24 | } 25 | 26 | /* Обработчик прерывания аппаратной ошибки */ 27 | void hardfault_handler(void) 28 | { 29 | for (;;); 30 | } 31 | -------------------------------------------------------------------------------- /03_TIM2/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | 03_TIM2 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.cdt.managedbuilder.core.genmakebuilder 10 | clean,full,incremental, 11 | 12 | 13 | 14 | 15 | org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder 16 | full,incremental, 17 | 18 | 19 | 20 | 21 | 22 | com.st.stm32cube.ide.mcu.MCUProjectNature 23 | org.eclipse.cdt.core.cnature 24 | com.st.stm32cube.ide.mcu.MCUCubeIdeServicesRevAev2ProjectNature 25 | com.st.stm32cube.ide.mcu.MCUManagedMakefileProjectNature 26 | com.st.stm32cube.ide.mcu.MCUSingleCpuProjectNature 27 | com.st.stm32cube.ide.mcu.MCURootProjectNature 28 | org.eclipse.cdt.managedbuilder.core.managedBuildNature 29 | org.eclipse.cdt.managedbuilder.core.ScannerConfigNature 30 | 31 | 32 | -------------------------------------------------------------------------------- /03_TIM2/03_TIM2.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /03_TIM2/Src/gpio.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | void GpioInit(void) 5 | { 6 | SET_BIT(RCC_AHB2ENR, RCC_AHB2ENR_GPIOBEN); // Подать тактовый сигнал на модуль GPIOB 7 | MODIFY_REG(GPIOB_MODER, GPIO_MODER_MODE8, 1< 2 | 3 | void GpioInit(void); 4 | void TIM2_Init(void); 5 | 6 | int main(void) 7 | { 8 | 9 | GpioInit(); //Настройка линий PB7 и PB8 на вывод 10 | TIM2_Init();//Настройка и запуск таймера TIM2 11 | 12 | while(1); 13 | } 14 | 15 | 16 | -------------------------------------------------------------------------------- /03_TIM2/Src/stm32f4.ld: -------------------------------------------------------------------------------- 1 | /* Точка входа - функция sturt_up */ 2 | ENTRY(start_up) 3 | 4 | /* 5 | Начальные адреса и размер RAM и FLASH 6 | FLASH также аппаратно отображается в адреса 0x00000000 - 0x00020000 7 | */ 8 | 9 | MEMORY 10 | { 11 | RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 32K 12 | FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 128K 13 | } 14 | 15 | /* Размер таблицы векторов прерывания */ 16 | _size_vector_table = 0x0400; 17 | 18 | /* 19 | Вершина стека 20 | Находится в конце RAM 21 | */ 22 | _estack = ORIGIN(RAM) + LENGTH(RAM); 23 | 24 | 25 | SECTIONS { 26 | 27 | /* Секция векторов прерывания */ 28 | .vectors : { 29 | . = ALIGN(4); 30 | _svector = .; 31 | /*ключевое слово KEEP сохраняет раздел даже если на него нет ссылок*/ 32 | KEEP(*(.vectors)); 33 | . = _svector + _size_vector_table; 34 | . = ALIGN(4); 35 | _evector = .; 36 | } > FLASH 37 | 38 | /* Секция кода программы и констант*/ 39 | .text : { 40 | *(.text*) 41 | *(.rodata*) 42 | } > FLASH 43 | 44 | /* Секция глобальных переменных, инициализированных нулем */ 45 | .bss : { 46 | _sbss = .; 47 | *(.bss*) 48 | *(COMMON) 49 | . = ALIGN(4); 50 | _ebss = .; 51 | } > RAM 52 | 53 | /* Секция глобальных переменных, инициализированных константами */ 54 | .data : { 55 | _sdata_ram = .; 56 | *(.data*) 57 | . = ALIGN(4); 58 | _edata_ram = .; 59 | } > RAM AT > FLASH 60 | 61 | } 62 | 63 | /* Начальный и конечный адрес секции .data во flash памяти */ 64 | _sdata_flash = LOADADDR(.data); 65 | _edata_flash = _sdata_flash + SIZEOF(.data); 66 | 67 | 68 | -------------------------------------------------------------------------------- /03_TIM2/Src/system_init.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* Константы определены в файле stm32f4.ld */ 4 | extern uint32_t _estack; 5 | extern uint32_t _sdata_ram, _edata_ram; 6 | extern uint32_t _sbss, _ebss; 7 | extern uint32_t _svector, _evector; 8 | extern uint32_t _sdata_flash, _edata_flash; 9 | 10 | int main(void); 11 | void SystemClock_Config(void); 12 | 13 | 14 | /* Точка входа */ 15 | void start_up(void) 16 | { 17 | uint32_t *src, *dst; 18 | 19 | /* Копирование данных секции .data из FLASH в RAM */ 20 | src = &_sdata_flash; 21 | dst = &_sdata_ram; 22 | while (dst < &_edata_ram) { 23 | *dst++ = *src++; 24 | } 25 | 26 | /* Запись нулей в область памяти секции .bss */ 27 | dst = &_sbss; 28 | while (dst < &_ebss) { 29 | *dst++ = 0; 30 | } 31 | 32 | SystemClock_Config(); 33 | main(); 34 | } 35 | 36 | 37 | 38 | 39 | void SystemClock_Config(void) 40 | { 41 | 42 | //Включить режим повышения выходного напряжения главного регулятора до 1,28 вольт 43 | CLEAR_BIT(PWR_CR5, PWR_CR5_R1MODE); 44 | 45 | //Установка задержки чтения FLASH памяти до 4-х тактов 46 | FLASH_ACR=FLASH_ACR_DBG_SWEN | FLASH_ACR_DCEN | FLASH_ACR_ICEN | FLASH_ACR_LATENCY_4WS ; 47 | while((FLASH_ACR & 0xf) != FLASH_ACR_LATENCY_4WS ); 48 | 49 | //Подключение внешнего кварцевого резонатора (HSE ON) 50 | SET_BIT(RCC_CR, RCC_CR_HSEON); 51 | while(READ_BIT(RCC_CR, RCC_CR_HSERDY) != (RCC_CR_HSERDY)); 52 | 53 | //Настройка PLL, используемого для SYSCLK домена 54 | //PLLM=6 (значение поля 5), PLLN=85 (значение поля 85), PLLR=2 (значение поля 0) 55 | MODIFY_REG(RCC_PLLCFGR, RCC_PLLCFGR_PLLSRC | RCC_PLLCFGR_PLLM | RCC_PLLCFGR_PLLN | RCC_PLLCFGR_PLLR, 56 | RCC_PLLCFGR_PLLSRC_HSE | 5 < 2 | 3 | 4 | void TIM2_Init(void) 5 | { 6 | 7 | SET_BIT(RCC_APB1ENR1, RCC_APB1ENR1_TIM2EN); // Подаем на TIM2 тактовую частоту 8 | TIM2_ARR = 85000000 - 1; // Загружаем Auto-reload register f = 170 000 000/(K+1) (2Hz -> 85000000 - 1) 9 | 10 | SET_BIT(NVIC_ISER0, (1 << 28)); // Разрешить в NVIC прерывание #28 (TIM2) 11 | SET_BIT(TIM2_DIER, TIM_DIER_UIE); // Разрешить прерывание по переполнению таймера 12 | SET_BIT(TIM2_CR1, TIM_CR1_CEN); // Включить таймер 13 | } 14 | 15 | 16 | void TIM2_IRQHandler(void) 17 | { 18 | CLEAR_BIT(TIM2_SR, TIM_SR_UIF); //Сброс флага переполнения 19 | INVERT_BIT(GPIOB_ODR, GPIO_ODR_OD7); //Инвертировать (PB7) 20 | INVERT_BIT(GPIOB_ODR, GPIO_ODR_OD8); //Инвертировать LD2 (PB8) 21 | } 22 | -------------------------------------------------------------------------------- /03_TIM2/Src/vectors.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void start_up(void); 4 | void nmi_handler(void); 5 | void hardfault_handler(void); 6 | void TIM2_IRQHandler(void); 7 | 8 | extern uint32_t _estack; 9 | 10 | /* Таблица векторов прерывания */ 11 | 12 | __attribute__ ((section(".vectors"),used))//Таблицу размещаем в секции .vectors 13 | uint32_t *vectors[] = { 14 | (uint32_t *) &_estack, //Вершина стека 15 | (uint32_t *) start_up, //Обработчик reset (точка входа) 16 | (uint32_t *) nmi_handler, //Обработчик немаскируемого прерывания 17 | (uint32_t *) hardfault_handler, //Обработчик прерывания аппаратной ошибки 18 | 0,0,0,0,0,0,0,0,0,0,0,0, //Окончание блока системных прерываний 19 | 0,0,0,0,0,0,0,0,0,0, //Прерывания 0 - 9 20 | 0,0,0,0,0,0,0,0,0,0, //Прерывания 10 -19 21 | 0,0,0,0,0,0,0,0, //Прерывания 20 -27 22 | (uint32_t *) TIM2_IRQHandler, //28 Обработчик прерывания от TIM2 23 | 0, //Прерывание 29 24 | 0,0,0,0,0,0,0,0,0, //Прерывания 30 -38 25 | }; 26 | 27 | 28 | /* Обработчик немаскируемого прерывания */ 29 | void nmi_handler(void) 30 | { 31 | for (;;); 32 | } 33 | 34 | /* Обработчик прерывания аппаратной ошибки */ 35 | void hardfault_handler(void) 36 | { 37 | for (;;); 38 | } 39 | -------------------------------------------------------------------------------- /04_TIM2_DAC/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | 04_TIM2_DAC 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.cdt.managedbuilder.core.genmakebuilder 10 | clean,full,incremental, 11 | 12 | 13 | 14 | 15 | org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder 16 | full,incremental, 17 | 18 | 19 | 20 | 21 | 22 | com.st.stm32cube.ide.mcu.MCUProjectNature 23 | org.eclipse.cdt.core.cnature 24 | com.st.stm32cube.ide.mcu.MCUCubeIdeServicesRevAev2ProjectNature 25 | com.st.stm32cube.ide.mcu.MCUManagedMakefileProjectNature 26 | com.st.stm32cube.ide.mcu.MCUSingleCpuProjectNature 27 | com.st.stm32cube.ide.mcu.MCURootProjectNature 28 | org.eclipse.cdt.managedbuilder.core.managedBuildNature 29 | org.eclipse.cdt.managedbuilder.core.ScannerConfigNature 30 | 31 | 32 | -------------------------------------------------------------------------------- /04_TIM2_DAC/Src/dac.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | //Выход DAC1 на PA4 5 | void DAC1_Init(void) 6 | { 7 | 8 | SET_BIT(RCC_AHB2ENR, RCC_AHB2ENR_DAC1EN ); // Подать тактовый сигнал на DAC1 9 | SET_BIT(DAC1_CR, 1); // Включить выход DAC1 10 | DAC1_DHR12R1 = 0; // Записать 0 в регистр данных DAC1 11 | 12 | } 13 | -------------------------------------------------------------------------------- /04_TIM2_DAC/Src/gpio.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | void GpioInit(void) 5 | { 6 | SET_BIT(RCC_AHB2ENR, RCC_AHB2ENR_GPIOBEN); // Подать тактовый сигнал на модуль GPIOB 7 | MODIFY_REG(GPIOB_MODER, GPIO_MODER_MODE8, 1< 2 | 3 | void GpioInit(void); 4 | void DAC1_Init(void); 5 | void TIM2_Init(void); 6 | 7 | int main(void) 8 | { 9 | 10 | GpioInit(); //Настройка линий PB7 и PB8 на вывод 11 | DAC1_Init();//Настройка ЦАП 12 | TIM2_Init();//Настройка и запуск таймера TIM2 13 | 14 | while(1); 15 | } 16 | 17 | 18 | -------------------------------------------------------------------------------- /04_TIM2_DAC/Src/stm32f4.ld: -------------------------------------------------------------------------------- 1 | /* Точка входа - функция sturt_up */ 2 | ENTRY(start_up) 3 | 4 | /* 5 | Начальные адреса и размер RAM и FLASH 6 | FLASH также аппаратно отображается в адреса 0x00000000 - 0x00020000 7 | */ 8 | 9 | MEMORY 10 | { 11 | RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 32K 12 | FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 128K 13 | } 14 | 15 | /* Размер таблицы векторов прерывания */ 16 | _size_vector_table = 0x0400; 17 | 18 | /* 19 | Вершина стека 20 | Находится в конце RAM 21 | */ 22 | _estack = ORIGIN(RAM) + LENGTH(RAM); 23 | 24 | 25 | SECTIONS { 26 | 27 | /* Секция векторов прерывания */ 28 | .vectors : { 29 | . = ALIGN(4); 30 | _svector = .; 31 | /*ключевое слово KEEP сохраняет раздел даже если на него нет ссылок*/ 32 | KEEP(*(.vectors)); 33 | . = _svector + _size_vector_table; 34 | . = ALIGN(4); 35 | _evector = .; 36 | } > FLASH 37 | 38 | /* Секция кода программы и констант*/ 39 | .text : { 40 | *(.text*) 41 | *(.rodata*) 42 | } > FLASH 43 | 44 | /* Секция глобальных переменных, инициализированных нулем */ 45 | .bss : { 46 | _sbss = .; 47 | *(.bss*) 48 | *(COMMON) 49 | . = ALIGN(4); 50 | _ebss = .; 51 | } > RAM 52 | 53 | /* Секция глобальных переменных, инициализированных константами */ 54 | .data : { 55 | _sdata_ram = .; 56 | *(.data*) 57 | . = ALIGN(4); 58 | _edata_ram = .; 59 | } > RAM AT > FLASH 60 | 61 | } 62 | 63 | /* Начальный и конечный адрес секции .data во flash памяти */ 64 | _sdata_flash = LOADADDR(.data); 65 | _edata_flash = _sdata_flash + SIZEOF(.data); 66 | 67 | 68 | -------------------------------------------------------------------------------- /04_TIM2_DAC/Src/system_init.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* Константы определены в файле stm32f4.ld */ 4 | extern uint32_t _estack; 5 | extern uint32_t _sdata_ram, _edata_ram; 6 | extern uint32_t _sbss, _ebss; 7 | extern uint32_t _svector, _evector; 8 | extern uint32_t _sdata_flash, _edata_flash; 9 | 10 | int main(void); 11 | void SystemClock_Config(void); 12 | 13 | /* Точка входа */ 14 | void start_up(void) 15 | { 16 | uint32_t *src, *dst; 17 | 18 | /* Копирование данных секции .data из FLASH в RAM */ 19 | src = &_sdata_flash; 20 | dst = &_sdata_ram; 21 | while (dst < &_edata_ram) { 22 | *dst++ = *src++; 23 | } 24 | 25 | /* Запись нулей в область памяти секции .bss */ 26 | dst = &_sbss; 27 | while (dst < &_ebss) { 28 | *dst++ = 0; 29 | } 30 | 31 | SystemClock_Config(); 32 | main(); 33 | } 34 | 35 | /* Обработчик немаскируемого прерывания */ 36 | void nmi_handler(void) 37 | { 38 | for (;;); 39 | } 40 | 41 | /* Обработчик прерывания аппаратной ошибки */ 42 | void hardfault_handler(void) 43 | { 44 | for (;;); 45 | } 46 | 47 | void SystemClock_Config(void) 48 | { 49 | 50 | //Включить режим повышения выходного напряжения главного регулятора до 1,28 вольт 51 | CLEAR_BIT(PWR_CR5, PWR_CR5_R1MODE); 52 | 53 | //Установка задержки чтения FLASH памяти до 4-х тактов 54 | FLASH_ACR=FLASH_ACR_DBG_SWEN | FLASH_ACR_DCEN | FLASH_ACR_ICEN | FLASH_ACR_LATENCY_4WS ; 55 | while((FLASH_ACR & 0xf) != FLASH_ACR_LATENCY_4WS ); 56 | 57 | //Подключение внешнего кварцевого резонатора (HSE ON) 58 | SET_BIT(RCC_CR, RCC_CR_HSEON); 59 | while(READ_BIT(RCC_CR, RCC_CR_HSERDY) != (RCC_CR_HSERDY)); 60 | 61 | //Настройка PLL, используемого для SYSCLK домена 62 | //PLLM=6 (значение поля 5), PLLN=85 (значение поля 85), PLLR=2 (значение поля 0) 63 | MODIFY_REG(RCC_PLLCFGR, RCC_PLLCFGR_PLLSRC | RCC_PLLCFGR_PLLM | RCC_PLLCFGR_PLLN | RCC_PLLCFGR_PLLR, 64 | RCC_PLLCFGR_PLLSRC_HSE | 5 < 2 | 3 | 4 | void TIM2_Init(void) 5 | { 6 | 7 | SET_BIT(RCC_APB1ENR1, RCC_APB1ENR1_TIM2EN); // Подаем на TIM2 тактовую частоту 8 | 9 | // Загружаем Auto-reload register f = 170 000 000/(TIM2_ARR + 1) (1 MHz -> 170 - 1) 10 | TIM2_ARR = 170 - 1; 11 | 12 | SET_BIT(NVIC_ISER0, (1 << 28)); // Разрешить в NVIC прерывание #28 (TIM2) 13 | SET_BIT(TIM2_DIER, TIM_DIER_UIE); // Разрешить прерывание по переполнению таймера 14 | SET_BIT(TIM2_CR1, TIM_CR1_CEN); // Включить таймер 15 | } 16 | 17 | void TIM2_IRQHandler(void) 18 | { 19 | // Переменная I увеличивается на 1 при каждом вызове обработчика прерывания 20 | static int I=0; 21 | 22 | CLEAR_BIT(TIM2_SR, TIM_SR_UIF); //Сброс флага переполнения 23 | DAC1_DHR12R1 = I++; // Запись в регистр данных DAC 12-ти младших разрядов переменной I 24 | 25 | } 26 | -------------------------------------------------------------------------------- /04_TIM2_DAC/Src/vectors.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void start_up(void); 4 | void nmi_handler(void); 5 | void hardfault_handler(void); 6 | void TIM2_IRQHandler(void); 7 | 8 | extern uint32_t _estack; 9 | 10 | /* Таблица векторов прерывания */ 11 | 12 | __attribute__ ((section(".vectors"),used))//Таблицу размещаем в секции .vectors 13 | uint32_t *vectors[] = { 14 | (uint32_t *) &_estack, //Вершина стека 15 | (uint32_t *) start_up, //Обработчик reset (точка входа) 16 | (uint32_t *) nmi_handler, //Обработчик немаскируемого прерывания 17 | (uint32_t *) hardfault_handler, //Обработчик прерывания аппаратной ошибки 18 | 0,0,0,0,0,0,0,0,0,0,0,0, //Окончание блока системных прерываний 19 | 0,0,0,0,0,0,0,0,0,0, //Прерывания 0 - 9 20 | 0,0,0,0,0,0,0,0,0,0, //Прерывания 10 -19 21 | 0,0,0,0,0,0,0,0, //Прерывания 20 -27 22 | (uint32_t *) TIM2_IRQHandler, //28 Обработчик прерывания от TIM2 23 | 0, //Прерывание 29 24 | 0,0,0,0,0,0,0,0,0, //Прерывания 30 -38 25 | }; 26 | 27 | -------------------------------------------------------------------------------- /05_TIM2_DAC_SIN/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | 04_TIM2_DAC 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.cdt.managedbuilder.core.genmakebuilder 10 | clean,full,incremental, 11 | 12 | 13 | 14 | 15 | org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder 16 | full,incremental, 17 | 18 | 19 | 20 | 21 | 22 | com.st.stm32cube.ide.mcu.MCUProjectNature 23 | org.eclipse.cdt.core.cnature 24 | com.st.stm32cube.ide.mcu.MCUCubeIdeServicesRevAev2ProjectNature 25 | com.st.stm32cube.ide.mcu.MCUManagedMakefileProjectNature 26 | com.st.stm32cube.ide.mcu.MCUSingleCpuProjectNature 27 | com.st.stm32cube.ide.mcu.MCURootProjectNature 28 | org.eclipse.cdt.managedbuilder.core.managedBuildNature 29 | org.eclipse.cdt.managedbuilder.core.ScannerConfigNature 30 | 31 | 32 | -------------------------------------------------------------------------------- /05_TIM2_DAC_SIN/Src/dac.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | //Выход DAC1 на PA4 5 | void DAC1_Init(void) 6 | { 7 | 8 | SET_BIT(RCC_AHB2ENR, RCC_AHB2ENR_DAC1EN ); // Подать тактовый сигнал на DAC1 9 | SET_BIT(DAC1_CR, 1); // Включить выход DAC1 10 | DAC1_DHR12R1 = 0; // Записать 0 в регистр данных DAC1 11 | 12 | } 13 | -------------------------------------------------------------------------------- /05_TIM2_DAC_SIN/Src/gpio.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | void GpioInit(void) 5 | { 6 | SET_BIT(RCC_AHB2ENR, RCC_AHB2ENR_GPIOBEN); // Подать тактовый сигнал на модуль GPIOB 7 | MODIFY_REG(GPIOB_MODER, GPIO_MODER_MODE8, 1< 2 | 3 | void GpioInit(void); 4 | void DAC1_Init(void); 5 | void TIM2_Init(void); 6 | 7 | int main(void) 8 | { 9 | 10 | GpioInit(); //Настройка GPIO 11 | DAC1_Init();//Настройка ЦАП 12 | TIM2_Init();//Настройка и запуск таймера TIM2 13 | 14 | while(1); 15 | 16 | } 17 | 18 | 19 | -------------------------------------------------------------------------------- /05_TIM2_DAC_SIN/Src/stm32f4.ld: -------------------------------------------------------------------------------- 1 | /* Точка входа - функция sturt_up */ 2 | ENTRY(start_up) 3 | 4 | /* 5 | Начальные адреса и размер RAM и FLASH 6 | FLASH также аппаратно отображается в адреса 0x00000000 - 0x00020000 7 | */ 8 | 9 | MEMORY 10 | { 11 | RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 32K 12 | FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 128K 13 | } 14 | 15 | /* Размер таблицы векторов прерывания */ 16 | _size_vector_table = 0x0400; 17 | 18 | /* 19 | Вершина стека 20 | Находится в конце RAM 21 | */ 22 | _estack = ORIGIN(RAM) + LENGTH(RAM); 23 | 24 | 25 | SECTIONS { 26 | 27 | /* Секция векторов прерывания */ 28 | .vectors : { 29 | . = ALIGN(4); 30 | _svector = .; 31 | /*ключевое слово KEEP сохраняет раздел даже если на него нет ссылок*/ 32 | KEEP(*(.vectors)); 33 | . = _svector + _size_vector_table; 34 | . = ALIGN(4); 35 | _evector = .; 36 | } > FLASH 37 | 38 | /* Секция кода программы и констант*/ 39 | .text : { 40 | *(.text*) 41 | *(.rodata*) 42 | } > FLASH 43 | 44 | /* Секция глобальных переменных, инициализированных нулем */ 45 | .bss : { 46 | _sbss = .; 47 | *(.bss*) 48 | *(COMMON) 49 | . = ALIGN(4); 50 | _ebss = .; 51 | } > RAM 52 | 53 | /* Секция глобальных переменных, инициализированных константами */ 54 | .data : { 55 | _sdata_ram = .; 56 | *(.data*) 57 | . = ALIGN(4); 58 | _edata_ram = .; 59 | } > RAM AT > FLASH 60 | 61 | } 62 | 63 | /* Начальный и конечный адрес секции .data во flash памяти */ 64 | _sdata_flash = LOADADDR(.data); 65 | _edata_flash = _sdata_flash + SIZEOF(.data); 66 | 67 | 68 | -------------------------------------------------------------------------------- /05_TIM2_DAC_SIN/Src/system_init.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* Константы определены в файле stm32f4.ld */ 4 | extern uint32_t _estack; 5 | extern uint32_t _sdata_ram, _edata_ram; 6 | extern uint32_t _sbss, _ebss; 7 | extern uint32_t _svector, _evector; 8 | extern uint32_t _sdata_flash, _edata_flash; 9 | 10 | int main(void); 11 | void SystemClock_Config(void); 12 | 13 | /* Точка входа */ 14 | void start_up(void) 15 | { 16 | uint32_t *src, *dst; 17 | 18 | /* Копирование данных секции .data из FLASH в RAM */ 19 | src = &_sdata_flash; 20 | dst = &_sdata_ram; 21 | while (dst < &_edata_ram) { 22 | *dst++ = *src++; 23 | } 24 | 25 | /* Запись нулей в область памяти секции .bss */ 26 | dst = &_sbss; 27 | while (dst < &_ebss) { 28 | *dst++ = 0; 29 | } 30 | 31 | /* Запуск FPU */ 32 | //SCB_CPACR |= ((3UL << (10*2))|(3UL << (11*2))); 33 | SET_BIT(SCB_CPACR, (3 << 20) | (3 << 22) ); /* set CP10 and CP11 Full Access */ 34 | 35 | SystemClock_Config(); 36 | main(); 37 | } 38 | 39 | /* Обработчик немаскируемого прерывания */ 40 | void nmi_handler(void) 41 | { 42 | for (;;); 43 | } 44 | 45 | /* Обработчик прерывания аппаратной ошибки */ 46 | void hardfault_handler(void) 47 | { 48 | for (;;); 49 | } 50 | 51 | void SystemClock_Config(void) 52 | { 53 | 54 | //Включить режим повышения выходного напряжения главного регулятора до 1,28 вольт 55 | CLEAR_BIT(PWR_CR5, PWR_CR5_R1MODE); 56 | 57 | //Установка задержки чтения FLASH памяти до 4-х тактов 58 | FLASH_ACR=FLASH_ACR_DBG_SWEN | FLASH_ACR_DCEN | FLASH_ACR_ICEN | FLASH_ACR_LATENCY_4WS ; 59 | while((FLASH_ACR & 0xf) != FLASH_ACR_LATENCY_4WS ); 60 | 61 | //Подключение внешнего кварцевого резонатора (HSE ON) 62 | SET_BIT(RCC_CR, RCC_CR_HSEON); 63 | while(READ_BIT(RCC_CR, RCC_CR_HSERDY) != (RCC_CR_HSERDY)); 64 | 65 | //Настройка PLL, используемого для SYSCLK домена 66 | //PLLM=6 (значение поля 5), PLLN=85 (значение поля 85), PLLR=2 (значение поля 0) 67 | MODIFY_REG(RCC_PLLCFGR, RCC_PLLCFGR_PLLSRC | RCC_PLLCFGR_PLLM | RCC_PLLCFGR_PLLN | RCC_PLLCFGR_PLLR, 68 | RCC_PLLCFGR_PLLSRC_HSE | 5 < 2 | 3 | 4 | void TIM2_Init(void) 5 | { 6 | 7 | SET_BIT(RCC_APB1ENR1, RCC_APB1ENR1_TIM2EN); // Подаем на TIM2 тактовую частоту 8 | 9 | // Загружаем Auto-reload register f = 170 000 000/(TIM2_ARR + 1) (1 MHz -> 170 - 1) 10 | TIM2_ARR = 170 - 1; 11 | 12 | SET_BIT(NVIC_ISER0, (1 << 28)); // Разрешить в NVIC прерывание #28 (TIM2) 13 | SET_BIT(TIM2_DIER, TIM_DIER_UIE); // Разрешить прерывание по переполнению таймера 14 | SET_BIT(TIM2_CR1, TIM_CR1_CEN); // Включить таймер 15 | } 16 | 17 | 18 | #define ds 0.000001 // Период дискретизации в секундах 19 | #define PI 3.1415926 // Число ПИ 20 | #define PW 0.031415926 // PI*f*ds при f = 10000 Hz 21 | 22 | 23 | void TIM2_IRQHandler(void) 24 | { 25 | 26 | static float R = 4 * PW * PW; //R=(2*PW))^2 27 | static float V=0; 28 | static float X = 4096/3.3 * 0.5;//Начальное значение - амплитуда сигнала 0.5 V 29 | static float S=1500; //Смещение DAC 30 | 31 | CLEAR_BIT(TIM2_SR, TIM_SR_UIF); //Сброс флага прерывания по переполнению таймера 32 | 33 | //Осциллятор 34 | V -= X*R; 35 | X += V; 36 | 37 | DAC1_DHR12R1 = X + S; 38 | 39 | } 40 | 41 | -------------------------------------------------------------------------------- /05_TIM2_DAC_SIN/Src/vectors.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void start_up(void); 4 | void nmi_handler(void); 5 | void hardfault_handler(void); 6 | void TIM2_IRQHandler(void); 7 | 8 | extern uint32_t _estack; 9 | 10 | /* Таблица векторов прерывания */ 11 | 12 | __attribute__ ((section(".vectors"),used))//Таблицу размещаем в секции .vectors 13 | uint32_t *vectors[] = { 14 | (uint32_t *) &_estack, //Вершина стека 15 | (uint32_t *) start_up, //Обработчик reset (точка входа) 16 | (uint32_t *) nmi_handler, //Обработчик немаскируемого прерывания 17 | (uint32_t *) hardfault_handler, //Обработчик прерывания аппаратной ошибки 18 | 0,0,0,0,0,0,0,0,0,0,0,0, //Окончание блока системных прерываний 19 | 0,0,0,0,0,0,0,0,0,0, //Прерывания 0 - 9 20 | 0,0,0,0,0,0,0,0,0,0, //Прерывания 10 -19 21 | 0,0,0,0,0,0,0,0, //Прерывания 20 -27 22 | (uint32_t *) TIM2_IRQHandler, //28 Обработчик прерывания от TIM2 23 | 0, //Прерывание 29 24 | 0,0,0,0,0,0,0,0,0, //Прерывания 30 -38 25 | }; 26 | 27 | -------------------------------------------------------------------------------- /06_ADC_DAC/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | 05_ADC_DAC_4MGz 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.cdt.managedbuilder.core.genmakebuilder 10 | clean,full,incremental, 11 | 12 | 13 | 14 | 15 | org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder 16 | full,incremental, 17 | 18 | 19 | 20 | 21 | 22 | com.st.stm32cube.ide.mcu.MCUProjectNature 23 | org.eclipse.cdt.core.cnature 24 | com.st.stm32cube.ide.mcu.MCUCubeIdeServicesRevAev2ProjectNature 25 | com.st.stm32cube.ide.mcu.MCUManagedMakefileProjectNature 26 | com.st.stm32cube.ide.mcu.MCUSingleCpuProjectNature 27 | com.st.stm32cube.ide.mcu.MCURootProjectNature 28 | org.eclipse.cdt.managedbuilder.core.managedBuildNature 29 | org.eclipse.cdt.managedbuilder.core.ScannerConfigNature 30 | 31 | 32 | -------------------------------------------------------------------------------- /06_ADC_DAC/06_ADC_DAC.launch: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /06_ADC_DAC/Src/adc.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | //Вход ADC1 на PA0 5 | void ADC1_init() 6 | { 7 | 8 | //Настройка тактирования ADC 9 | SET_BIT(RCC_CCIPR, 1 << 29 ); // Выбрать системный clock в качестве тактового сигнала для ADC 10 | SET_BIT(RCC_AHB2ENR, 1 << 13 ); // Подать тактовый сигнал на модуль ADC12 11 | SET_BIT(ADC12_COMMON_CCR, 2 << 16 ); // Выбрать в качестве тактового сигнала adc_hclk/2 12 | 13 | //Настройка режима ADC 14 | ADC1_CR = 0; // Сброс всех бит в ADC1_CR (ADEN = 0 для обеспечения конфигурирования) 15 | SET_BIT(ADC1_CR, 1 << 28); // Включить опорное напряжение ADC 16 | // Запуск преобразования от TIM2_TRG0 (канал 11)(биты 5- 11), перезапись разрешена (бит 12) 17 | ADC1_CFGR = (1 << 12)+(1 << 10)+ (11 << 5); 18 | ADC1_SQR1 = (1 << 6); // Выбрать входной канал 1 (PA0) 19 | 20 | //Настройка прерывания 21 | ADC1_IER = (1 << 3); // Разрешить прерывание по окончанию преобразования в ADC 22 | SET_BIT(NVIC_ISER0, (1 << 18)); // Разрешить в NVIC прерывание #18 (ADC1) 23 | 24 | SET_BIT(ADC1_CR, (1 << 0) | (1 << 2));// Включить ADC1 и начать преобразование 25 | SET_BIT(TIM2_CR1, TIM_CR1_CEN); //Запуск TIM2 - cтарт генерации сигнала дискретизации для ADC1 26 | 27 | } 28 | 29 | void ADC1_IRQHandler(void) 30 | { 31 | SET_BIT(ADC1_ISR, (1 << 3)); // Сброс флага переполнения в ADC1 32 | DAC1_DHR12R1 = ADC1_DR; // Записать данные из АЦП в ЦАП 33 | } 34 | -------------------------------------------------------------------------------- /06_ADC_DAC/Src/dac.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | //Выход DAC1 на PA4 5 | void DAC1_Init(void) 6 | { 7 | 8 | SET_BIT(RCC_AHB2ENR, RCC_AHB2ENR_DAC1EN ); // Подать тактовый сигнал на DAC1 9 | SET_BIT(DAC1_CR, 1); // Включить выход DAC1 10 | DAC1_DHR12R1 = 0; // Записать 0 в регистр данных DAC1 11 | 12 | } 13 | -------------------------------------------------------------------------------- /06_ADC_DAC/Src/gpio.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | void GpioInit(void) 5 | { 6 | SET_BIT(RCC_AHB2ENR, RCC_AHB2ENR_GPIOAEN | RCC_AHB2ENR_GPIOBEN); // Подать тактовый сигнал на GPIOA и GPIOB 7 | MODIFY_REG(GPIOB_MODER, GPIO_MODER_MODE8, 1< 2 | 3 | void GpioInit(void); 4 | void TIM2_Init(void); 5 | void DAC1_Init(void); 6 | void ADC1_init(); 7 | 8 | int main(void) 9 | { 10 | 11 | GpioInit(); //Настройка GPIO 12 | TIM2_Init();//Настройка TIM2 13 | DAC1_Init();//Настройка таймера ЦАП 14 | ADC1_init();//Настройка и запуск АЦП 15 | 16 | while(1); 17 | } 18 | 19 | -------------------------------------------------------------------------------- /06_ADC_DAC/Src/stm32f4.ld: -------------------------------------------------------------------------------- 1 | /* Точка входа - функция sturt_up */ 2 | ENTRY(start_up) 3 | 4 | /* 5 | Начальные адреса и размер RAM и FLASH 6 | FLASH также аппаратно отображается в адреса 0x00000000 - 0x00020000 7 | */ 8 | 9 | MEMORY 10 | { 11 | RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 32K 12 | FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 128K 13 | } 14 | 15 | /* Размер таблицы векторов прерывания */ 16 | _size_vector_table = 0x0400; 17 | 18 | /* 19 | Вершина стека 20 | Находится в конце RAM 21 | */ 22 | _estack = ORIGIN(RAM) + LENGTH(RAM); 23 | 24 | 25 | SECTIONS { 26 | 27 | /* Секция векторов прерывания */ 28 | .vectors : { 29 | . = ALIGN(4); 30 | _svector = .; 31 | /*ключевое слово KEEP сохраняет раздел даже если на него нет ссылок*/ 32 | KEEP(*(.vectors)); 33 | . = _svector + _size_vector_table; 34 | . = ALIGN(4); 35 | _evector = .; 36 | } > FLASH 37 | 38 | /* Секция кода программы и констант*/ 39 | .text : { 40 | *(.text*) 41 | *(.rodata*) 42 | } > FLASH 43 | 44 | /* Секция глобальных переменных, инициализированных нулем */ 45 | .bss : { 46 | _sbss = .; 47 | *(.bss*) 48 | *(COMMON) 49 | . = ALIGN(4); 50 | _ebss = .; 51 | } > RAM 52 | 53 | /* Секция глобальных переменных, инициализированных константами */ 54 | .data : { 55 | _sdata_ram = .; 56 | *(.data*) 57 | . = ALIGN(4); 58 | _edata_ram = .; 59 | } > RAM AT > FLASH 60 | 61 | } 62 | 63 | /* Начальный и конечный адрес секции .data во flash памяти */ 64 | _sdata_flash = LOADADDR(.data); 65 | _edata_flash = _sdata_flash + SIZEOF(.data); 66 | 67 | 68 | -------------------------------------------------------------------------------- /06_ADC_DAC/Src/system_init.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* Константы определены в файле stm32f4.ld */ 4 | extern uint32_t _estack; 5 | extern uint32_t _sdata_ram, _edata_ram; 6 | extern uint32_t _sbss, _ebss; 7 | extern uint32_t _svector, _evector; 8 | extern uint32_t _sdata_flash, _edata_flash; 9 | 10 | void SystemClock_Config(void); 11 | int main(void); 12 | 13 | /* Точка входа */ 14 | void start_up(void) 15 | { 16 | uint32_t *src, *dst; 17 | 18 | /* Копирование данных секции .data из FLASH в RAM */ 19 | src = &_sdata_flash; 20 | dst = &_sdata_ram; 21 | while (dst < &_edata_ram) { 22 | *dst++ = *src++; 23 | } 24 | 25 | /* Запись нулей в область памяти секции .bss */ 26 | dst = &_sbss; 27 | while (dst < &_ebss) { 28 | *dst++ = 0; 29 | } 30 | 31 | /* FPU settings ------------------------------------------------------------*/ 32 | 33 | SCB_CPACR |= ((3UL << (10*2))|(3UL << (11*2))); /* set CP10 and CP11 Full Access */ 34 | 35 | SystemClock_Config(); 36 | main(); 37 | } 38 | 39 | 40 | 41 | void SystemClock_Config(void) 42 | { 43 | 44 | //Включить режим повышения выходного напряжения главного регулятора до 1,28 вольт 45 | CLEAR_BIT(PWR_CR5, PWR_CR5_R1MODE); 46 | 47 | //Установка задержки чтения FLASH памяти до 4-х тактов 48 | FLASH_ACR=FLASH_ACR_DBG_SWEN | FLASH_ACR_DCEN | FLASH_ACR_ICEN | FLASH_ACR_LATENCY_4WS ; 49 | while((FLASH_ACR & 0xf) != FLASH_ACR_LATENCY_4WS ); 50 | 51 | //Подключение внешнего кварцевого резонатора (HSE ON) 52 | SET_BIT(RCC_CR, RCC_CR_HSEON); 53 | while(READ_BIT(RCC_CR, RCC_CR_HSERDY) != (RCC_CR_HSERDY)); 54 | 55 | //Настройка PLL, используемого для SYSCLK домена 56 | //PLLM=6 (значение поля 5), PLLN=85 (значение поля 85), PLLR=2 (значение поля 0) 57 | MODIFY_REG(RCC_PLLCFGR, RCC_PLLCFGR_PLLSRC | RCC_PLLCFGR_PLLM | RCC_PLLCFGR_PLLN | RCC_PLLCFGR_PLLR, 58 | RCC_PLLCFGR_PLLSRC_HSE | 5 < 2 | 3 | void TIM2_Init(void) 4 | { 5 | 6 | SET_BIT(RCC_APB1ENR1, RCC_APB1ENR1_TIM2EN); // Подаем на TIM2 тактовую частоту 7 | TIM2_ARR = 170-1; // Загружаем Auto-reload register f = 170 000 000/(TIM2_ARR+1), 1 MHz -> (170 - 1) 8 | TIM2_CR2 = TIM_CR2_MMS_1; // Выбор мастер режима таймера для возможности тактирования ADC 9 | 10 | } 11 | 12 | -------------------------------------------------------------------------------- /06_ADC_DAC/Src/vectors.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void start_up(void); 4 | void nmi_handler(void); 5 | void hardfault_handler(void); 6 | void ADC1_IRQHandler(void); 7 | 8 | extern uint32_t _estack; 9 | 10 | /* Таблица векторов прерывания */ 11 | 12 | __attribute__ ((section(".vectors"),used))//Таблицу размещаем в секции .vectors 13 | uint32_t *vectors[] = { 14 | (uint32_t *) &_estack, //Вершина стека 15 | (uint32_t *) start_up, //Обработчик reset (точка входа) 16 | (uint32_t *) nmi_handler, //Обработчик немаскируемого прерывания 17 | (uint32_t *) hardfault_handler, //Обработчик прерывания аппаратной ошибки 18 | 0,0,0,0,0,0,0,0,0,0,0,0, //Окончание блока системных прерываний 19 | 0,0,0,0,0,0,0,0,0,0, //Прерывания 0 - 9 20 | 0,0,0,0,0,0,0,0, //Прерывания 10 -17 21 | (uint32_t *) ADC1_IRQHandler, //Прерывание 18 22 | 0 //Прерывание 19 23 | }; 24 | 25 | /* Обработчик немаскируемого прерывания */ 26 | void nmi_handler(void) 27 | { 28 | for (;;); 29 | } 30 | 31 | /* Обработчик прерывания аппаратной ошибки */ 32 | void hardfault_handler(void) 33 | { 34 | for (;;); 35 | } 36 | -------------------------------------------------------------------------------- /07_ADC_DAC_FIL/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | 07_ADC_DAC_FIL 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.cdt.managedbuilder.core.genmakebuilder 10 | clean,full,incremental, 11 | 12 | 13 | 14 | 15 | org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder 16 | full,incremental, 17 | 18 | 19 | 20 | 21 | 22 | com.st.stm32cube.ide.mcu.MCUProjectNature 23 | org.eclipse.cdt.core.cnature 24 | com.st.stm32cube.ide.mcu.MCUCubeIdeServicesRevAev2ProjectNature 25 | com.st.stm32cube.ide.mcu.MCUManagedMakefileProjectNature 26 | com.st.stm32cube.ide.mcu.MCUSingleCpuProjectNature 27 | com.st.stm32cube.ide.mcu.MCURootProjectNature 28 | org.eclipse.cdt.managedbuilder.core.managedBuildNature 29 | org.eclipse.cdt.managedbuilder.core.ScannerConfigNature 30 | 31 | 32 | -------------------------------------------------------------------------------- /07_ADC_DAC_FIL/Src/adc.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | //Вход ADC1 на PA0 5 | void ADC1_init() 6 | { 7 | 8 | //Настройка тактирования ADC 9 | SET_BIT(RCC_CCIPR, 1 << 29 ); // Выбрать системный clock в качестве тактового сигнала для ADC 10 | SET_BIT(RCC_AHB2ENR, 1 << 13 ); // Подать тактовый сигнал на модуль ADC12 11 | SET_BIT(ADC12_COMMON_CCR, 2 << 16 ); // Выбрать в качестве тактового сигнала adc_hclk/2 12 | 13 | //Настройка режима ADC 14 | ADC1_CR = 0; // Сброс всех бит в ADC1_CR (ADEN = 0 для обеспечения конфигурирования) 15 | SET_BIT(ADC1_CR, 1 << 28); // Включить опорное напряжение ADC 16 | // Запуск преобразования от TIM2_TRG0 (канал 11)(биты 5- 11), перезапись разрешена (бит 12) 17 | ADC1_CFGR = (1 << 12)+(1 << 10)+ (11 << 5); 18 | ADC1_SQR1 = (1 << 6); // Выбрать входной канал 1 (PA0) 19 | 20 | //Настройка прерывания 21 | ADC1_IER = (1 << 3); // Разрешить прерывание по окончанию преобразования в ADC 22 | SET_BIT(NVIC_ISER0, (1 << 18)); // Разрешить в NVIC прерывание #18 (ADC1) 23 | 24 | SET_BIT(ADC1_CR, (1 << 0) | (1 << 2));// Включить ADC1 и начать преобразование 25 | SET_BIT(TIM2_CR1, TIM_CR1_CEN); //Запуск TIM2 - cтарт генерации сигнала дискретизации для ADC1 26 | 27 | } 28 | 29 | 30 | void ADC1_IRQHandler(void) 31 | { 32 | 33 | //Параметры фильтра на частоту 100 KHz 34 | //R ≈ (2*Sin(PI*Wr))^2, где Wr = Fr/Fd, fr = 100 KHz, Fd = 1000 KHz 35 | static float R = 0.381965999; 36 | static float L = 0.01; 37 | 38 | //Начальные значения 39 | static float X = 0; 40 | static float V = 0; 41 | 42 | //Смещение DAC отдельная переменная ускоряет преобразование из float в int 43 | static float S = 1800; 44 | 45 | SET_BIT(ADC1_ISR, (1 << 3)); // Сброс флага переполнения в ADC1 46 | 47 | //Фильтр 48 | X += (int)ADC1_DR- S; 49 | V -= X * R; 50 | X += V - X * L; 51 | 52 | //Запись в DAC 53 | DAC1_DHR12R1 = X + S; 54 | 55 | } 56 | 57 | -------------------------------------------------------------------------------- /07_ADC_DAC_FIL/Src/dac.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | //Выход DAC1 на PA4 5 | void DAC1_Init(void) 6 | { 7 | 8 | SET_BIT(RCC_AHB2ENR, RCC_AHB2ENR_DAC1EN ); // Подать тактовый сигнал на DAC1 9 | SET_BIT(DAC1_CR, 1); // Включить выход DAC1 10 | DAC1_DHR12R1 = 0; // Записать 0 в регистр данных DAC1 11 | 12 | } 13 | -------------------------------------------------------------------------------- /07_ADC_DAC_FIL/Src/gpio.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | void GpioInit(void) 5 | { 6 | SET_BIT(RCC_AHB2ENR, RCC_AHB2ENR_GPIOAEN | RCC_AHB2ENR_GPIOBEN); // Подать тактовый сигнал на GPIOA и GPIOB 7 | MODIFY_REG(GPIOB_MODER, GPIO_MODER_MODE8, 1< 2 | 3 | void GpioInit(void); 4 | void TIM2_Init(void); 5 | void DAC1_Init(void); 6 | void ADC1_init(); 7 | 8 | int main(void) 9 | { 10 | 11 | GpioInit(); //Настройка GPIO 12 | TIM2_Init();//Настройка TIM2 13 | DAC1_Init();//Настройка ЦАП 14 | ADC1_init();//Настройка и запуск АЦП 15 | 16 | while(1); 17 | } 18 | 19 | -------------------------------------------------------------------------------- /07_ADC_DAC_FIL/Src/stm32f4.ld: -------------------------------------------------------------------------------- 1 | /* Точка входа - функция sturt_up */ 2 | ENTRY(start_up) 3 | 4 | /* 5 | Начальные адреса и размер RAM и FLASH 6 | FLASH также аппаратно отображается в адреса 0x00000000 - 0x00020000 7 | */ 8 | 9 | MEMORY 10 | { 11 | RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 32K 12 | FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 128K 13 | } 14 | 15 | /* Размер таблицы векторов прерывания */ 16 | _size_vector_table = 0x0400; 17 | 18 | /* 19 | Вершина стека 20 | Находится в конце RAM 21 | */ 22 | _estack = ORIGIN(RAM) + LENGTH(RAM); 23 | 24 | 25 | SECTIONS { 26 | 27 | /* Секция векторов прерывания */ 28 | .vectors : { 29 | . = ALIGN(4); 30 | _svector = .; 31 | /*ключевое слово KEEP сохраняет раздел даже если на него нет ссылок*/ 32 | KEEP(*(.vectors)); 33 | . = _svector + _size_vector_table; 34 | . = ALIGN(4); 35 | _evector = .; 36 | } > FLASH 37 | 38 | /* Секция кода программы и констант*/ 39 | .text : { 40 | *(.text*) 41 | *(.rodata*) 42 | } > FLASH 43 | 44 | /* Секция глобальных переменных, инициализированных нулем */ 45 | .bss : { 46 | _sbss = .; 47 | *(.bss*) 48 | *(COMMON) 49 | . = ALIGN(4); 50 | _ebss = .; 51 | } > RAM 52 | 53 | /* Секция глобальных переменных, инициализированных константами */ 54 | .data : { 55 | _sdata_ram = .; 56 | *(.data*) 57 | . = ALIGN(4); 58 | _edata_ram = .; 59 | } > RAM AT > FLASH 60 | 61 | } 62 | 63 | /* Начальный и конечный адрес секции .data во flash памяти */ 64 | _sdata_flash = LOADADDR(.data); 65 | _edata_flash = _sdata_flash + SIZEOF(.data); 66 | 67 | 68 | -------------------------------------------------------------------------------- /07_ADC_DAC_FIL/Src/system_init.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* Константы определены в файле stm32f4.ld */ 4 | extern uint32_t _estack; 5 | extern uint32_t _sdata_ram, _edata_ram; 6 | extern uint32_t _sbss, _ebss; 7 | extern uint32_t _svector, _evector; 8 | extern uint32_t _sdata_flash, _edata_flash; 9 | 10 | void SystemClock_Config(void); 11 | int main(void); 12 | 13 | /* Точка входа */ 14 | void start_up(void) 15 | { 16 | uint32_t *src, *dst; 17 | 18 | /* Копирование данных секции .data из FLASH в RAM */ 19 | src = &_sdata_flash; 20 | dst = &_sdata_ram; 21 | while (dst < &_edata_ram) { 22 | *dst++ = *src++; 23 | } 24 | 25 | /* Запись нулей в область памяти секции .bss */ 26 | dst = &_sbss; 27 | while (dst < &_ebss) { 28 | *dst++ = 0; 29 | } 30 | 31 | /* FPU settings ------------------------------------------------------------*/ 32 | 33 | SCB_CPACR |= ((3UL << (10*2))|(3UL << (11*2))); /* set CP10 and CP11 Full Access */ 34 | 35 | SystemClock_Config(); 36 | main(); 37 | } 38 | 39 | 40 | 41 | void SystemClock_Config(void) 42 | { 43 | 44 | //Включить режим повышения выходного напряжения главного регулятора до 1,28 вольт 45 | CLEAR_BIT(PWR_CR5, PWR_CR5_R1MODE); 46 | 47 | //Установка задержки чтения FLASH памяти до 4-х тактов 48 | FLASH_ACR=FLASH_ACR_DBG_SWEN | FLASH_ACR_DCEN | FLASH_ACR_ICEN | FLASH_ACR_LATENCY_4WS ; 49 | while((FLASH_ACR & 0xf) != FLASH_ACR_LATENCY_4WS ); 50 | 51 | //Подключение внешнего кварцевого резонатора (HSE ON) 52 | SET_BIT(RCC_CR, RCC_CR_HSEON); 53 | while(READ_BIT(RCC_CR, RCC_CR_HSERDY) != (RCC_CR_HSERDY)); 54 | 55 | //Настройка PLL, используемого для SYSCLK домена 56 | //PLLM=6 (значение поля 5), PLLN=85 (значение поля 85), PLLR=2 (значение поля 0) 57 | MODIFY_REG(RCC_PLLCFGR, RCC_PLLCFGR_PLLSRC | RCC_PLLCFGR_PLLM | RCC_PLLCFGR_PLLN | RCC_PLLCFGR_PLLR, 58 | RCC_PLLCFGR_PLLSRC_HSE | 5 < 2 | 3 | void TIM2_Init(void) 4 | { 5 | 6 | SET_BIT(RCC_APB1ENR1, RCC_APB1ENR1_TIM2EN); // Подаем на TIM2 тактовую частоту 7 | TIM2_ARR = 170 - 1; // Загружаем Auto-reload register f = 170 000 000/(TIM2_ARR+1), 1 MHz -> 170 -1 8 | TIM2_CR2 = TIM_CR2_MMS_1; // Выбор мастер режима таймера для возможности тактирования ADC 9 | 10 | } 11 | 12 | -------------------------------------------------------------------------------- /07_ADC_DAC_FIL/Src/vectors.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void start_up(void); 4 | void nmi_handler(void); 5 | void hardfault_handler(void); 6 | void ADC1_IRQHandler(void); 7 | 8 | extern uint32_t _estack; 9 | 10 | /* Таблица векторов прерывания */ 11 | 12 | __attribute__ ((section(".vectors"),used))//Таблицу размещаем в секции .vectors 13 | uint32_t *vectors[] = { 14 | (uint32_t *) &_estack, //Вершина стека 15 | (uint32_t *) start_up, //Обработчик reset (точка входа) 16 | (uint32_t *) nmi_handler, //Обработчик немаскируемого прерывания 17 | (uint32_t *) hardfault_handler, //Обработчик прерывания аппаратной ошибки 18 | 0,0,0,0,0,0,0,0,0,0,0,0, //Окончание блока системных прерываний 19 | 0,0,0,0,0,0,0,0,0,0, //Прерывания 0 - 9 20 | 0,0,0,0,0,0,0,0, //Прерывания 10 -17 21 | (uint32_t *) ADC1_IRQHandler, //Прерывание 18 22 | 0 //Прерывание 19 23 | }; 24 | 25 | /* Обработчик немаскируемого прерывания */ 26 | void nmi_handler(void) 27 | { 28 | for (;;); 29 | } 30 | 31 | /* Обработчик прерывания аппаратной ошибки */ 32 | void hardfault_handler(void) 33 | { 34 | for (;;); 35 | } 36 | -------------------------------------------------------------------------------- /08_ADC_DAC_FIL_DET/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | 08_ADC_DAC_FIL_DET 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.cdt.managedbuilder.core.genmakebuilder 10 | clean,full,incremental, 11 | 12 | 13 | 14 | 15 | org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder 16 | full,incremental, 17 | 18 | 19 | 20 | 21 | 22 | com.st.stm32cube.ide.mcu.MCUProjectNature 23 | org.eclipse.cdt.core.cnature 24 | com.st.stm32cube.ide.mcu.MCUCubeIdeServicesRevAev2ProjectNature 25 | com.st.stm32cube.ide.mcu.MCUManagedMakefileProjectNature 26 | com.st.stm32cube.ide.mcu.MCUSingleCpuProjectNature 27 | com.st.stm32cube.ide.mcu.MCURootProjectNature 28 | org.eclipse.cdt.managedbuilder.core.managedBuildNature 29 | org.eclipse.cdt.managedbuilder.core.ScannerConfigNature 30 | 31 | 32 | -------------------------------------------------------------------------------- /08_ADC_DAC_FIL_DET/Src/adc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define FD 1000 //Частота дискретизации KHz 5 | #define FR 100 //Частота фильтра KHz 6 | #define FLPF 1 //Частота перегиба ФНЧ KHz 7 | static float R; //Параметр фильтра, зависящий от частоты 8 | 9 | //Вход ADC1 на PA0 10 | void ADC1_init() 11 | { 12 | 13 | //Настройка тактирования ADC 14 | SET_BIT(RCC_CCIPR, 1 << 29 ); // Выбрать системный clock в качестве тактового сигнала для ADC 15 | SET_BIT(RCC_AHB2ENR, 1 << 13 ); // Подать тактовый сигнал на модуль ADC12 16 | SET_BIT(ADC12_COMMON_CCR, 2 << 16 ); // Выбрать в качестве тактового сигнала adc_hclk/2 17 | 18 | //Настройка режима ADC 19 | ADC1_CR = 0; // Сброс всех бит в ADC1_CR (ADEN = 0 для обеспечения конфигурирования) 20 | SET_BIT(ADC1_CR, 1 << 28); // Включить опорное напряжение ADC 21 | // Запуск преобразования от TIM2_TRG0 (канал 11)(биты 5- 11), перезапись разрешена (бит 12) 22 | ADC1_CFGR = (1 << 12)+(1 << 10)+ (11 << 5); 23 | ADC1_SQR1 = (1 << 6); // Выбрать входной канал 1 (PA0) 24 | // ADC1_DIFSEL = 2; // ADC1 канал 1 в дифференциальном режиме 25 | 26 | //Настройка прерывания 27 | ADC1_IER = (1 << 3); // Разрешить прерывание по окончанию преобразования в ADC 28 | SET_BIT(NVIC_ISER0, (1 << 18)); // Разрешить в NVIC прерывание #18 (ADC1) 29 | 30 | SET_BIT(ADC1_CR, (1 << 0) | (1 << 2));// Включить ADC1 и начать преобразование 31 | SET_BIT(TIM2_CR1, TIM_CR1_CEN); //Запуск TIM2 - cтарт генерации сигнала дискретизации для ADC1 32 | 33 | // Параметр фильтра зависящий от частоты R=(2*Sin(PI*W))^2 34 | R = (2*sin(M_PI*FR/FD)); 35 | R *= R; 36 | } 37 | 38 | 39 | void ADC1_IRQHandler(void) 40 | { 41 | 42 | //Параметр, определяющий полосу пропускания фильтра dF 43 | //L ≈ 5.6 * Fd/FD 44 | static float L = 0.004; 45 | 46 | //Начальные значения переменных фильтра 47 | static float X = 0; 48 | static float V = 0; 49 | 50 | //Параметр интегрирующей цепочки 51 | static float K = 2*M_PI*FLPF/FD; //K = 2PI*f/fd 52 | 53 | //Начальные значения переменных детектора 54 | static float U = 0; 55 | float D; 56 | int out; 57 | 58 | //Смещение для ADC и DAC 59 | static int S_ADC = 2000; 60 | static int S_DAC = 100; 61 | 62 | // Сброс флага переполнения в ADC1 63 | SET_BIT(ADC1_ISR, (1 << 3)); 64 | 65 | //Фильтр 66 | X += (int)ADC1_DR- S_ADC; 67 | V -= X * R; 68 | X += V - X * L; 69 | 70 | //Детектор 71 | D = fabs(X); 72 | U += (D - U) * K; // Интегрирующая цепь 73 | out = U + S_DAC; 74 | 75 | // Ограничитель, предотвращает переполнение DAC при сильном сигнале 76 | if( out > 4000) out = 4000; 77 | 78 | //Запись в DAC 79 | DAC1_DHR12R1 = out; 80 | 81 | } 82 | 83 | -------------------------------------------------------------------------------- /08_ADC_DAC_FIL_DET/Src/dac.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | //Выход DAC1 на PA4 5 | void DAC1_Init(void) 6 | { 7 | 8 | SET_BIT(RCC_AHB2ENR, RCC_AHB2ENR_DAC1EN ); // Подать тактовый сигнал на DAC1 9 | SET_BIT(DAC1_CR, 1); // Включить выход DAC1 10 | DAC1_DHR12R1 = 0; // Записать 0 в регистр данных DAC1 11 | 12 | } 13 | -------------------------------------------------------------------------------- /08_ADC_DAC_FIL_DET/Src/gpio.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | void GpioInit(void) 5 | { 6 | SET_BIT(RCC_AHB2ENR, RCC_AHB2ENR_GPIOAEN | RCC_AHB2ENR_GPIOBEN); // Подать тактовый сигнал на GPIOA и GPIOB 7 | MODIFY_REG(GPIOB_MODER, GPIO_MODER_MODE8, 1< 2 | 3 | void GpioInit(void); 4 | void TIM2_Init(void); 5 | void DAC1_Init(void); 6 | void ADC1_init(); 7 | 8 | int main(void) 9 | { 10 | 11 | GpioInit(); //Настройка GPIO 12 | TIM2_Init();//Настройка TIM2 13 | DAC1_Init();//Настройка ЦАП 14 | ADC1_init();//Настройка и запуск АЦП 15 | 16 | while(1); 17 | } 18 | 19 | -------------------------------------------------------------------------------- /08_ADC_DAC_FIL_DET/Src/stm32f4.ld: -------------------------------------------------------------------------------- 1 | /* Точка входа - функция sturt_up */ 2 | ENTRY(start_up) 3 | 4 | /* 5 | Начальные адреса и размер RAM и FLASH 6 | FLASH также аппаратно отображается в адреса 0x00000000 - 0x00020000 7 | */ 8 | 9 | MEMORY 10 | { 11 | RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 32K 12 | FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 128K 13 | } 14 | 15 | /* Размер таблицы векторов прерывания */ 16 | _size_vector_table = 0x0400; 17 | 18 | /* 19 | Вершина стека 20 | Находится в конце RAM 21 | */ 22 | _estack = ORIGIN(RAM) + LENGTH(RAM); 23 | 24 | 25 | SECTIONS { 26 | 27 | /* Секция векторов прерывания */ 28 | .vectors : { 29 | . = ALIGN(4); 30 | _svector = .; 31 | /*ключевое слово KEEP сохраняет раздел даже если на него нет ссылок*/ 32 | KEEP(*(.vectors)); 33 | . = _svector + _size_vector_table; 34 | . = ALIGN(4); 35 | _evector = .; 36 | } > FLASH 37 | 38 | /* Секция кода программы и констант*/ 39 | .text : { 40 | *(.text*) 41 | *(.rodata*) 42 | } > FLASH 43 | 44 | /* Секция глобальных переменных, инициализированных нулем */ 45 | .bss : { 46 | _sbss = .; 47 | *(.bss*) 48 | *(COMMON) 49 | . = ALIGN(4); 50 | _ebss = .; 51 | } > RAM 52 | 53 | /* Секция глобальных переменных, инициализированных константами */ 54 | .data : { 55 | _sdata_ram = .; 56 | *(.data*) 57 | . = ALIGN(4); 58 | _edata_ram = .; 59 | } > RAM AT > FLASH 60 | 61 | } 62 | 63 | /* Начальный и конечный адрес секции .data во flash памяти */ 64 | _sdata_flash = LOADADDR(.data); 65 | _edata_flash = _sdata_flash + SIZEOF(.data); 66 | 67 | 68 | -------------------------------------------------------------------------------- /08_ADC_DAC_FIL_DET/Src/system_init.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* Константы определены в файле stm32f4.ld */ 4 | extern uint32_t _estack; 5 | extern uint32_t _sdata_ram, _edata_ram; 6 | extern uint32_t _sbss, _ebss; 7 | extern uint32_t _svector, _evector; 8 | extern uint32_t _sdata_flash, _edata_flash; 9 | 10 | void SystemClock_Config(void); 11 | int main(void); 12 | 13 | /* Точка входа */ 14 | void start_up(void) 15 | { 16 | uint32_t *src, *dst; 17 | 18 | /* Копирование данных секции .data из FLASH в RAM */ 19 | src = &_sdata_flash; 20 | dst = &_sdata_ram; 21 | while (dst < &_edata_ram) { 22 | *dst++ = *src++; 23 | } 24 | 25 | /* Запись нулей в область памяти секции .bss */ 26 | dst = &_sbss; 27 | while (dst < &_ebss) { 28 | *dst++ = 0; 29 | } 30 | 31 | /* FPU settings ------------------------------------------------------------*/ 32 | 33 | SCB_CPACR |= ((3UL << (10*2))|(3UL << (11*2))); /* set CP10 and CP11 Full Access */ 34 | 35 | SystemClock_Config(); 36 | main(); 37 | } 38 | 39 | 40 | 41 | void SystemClock_Config(void) 42 | { 43 | 44 | //Включить режим повышения выходного напряжения главного регулятора до 1,28 вольт 45 | CLEAR_BIT(PWR_CR5, PWR_CR5_R1MODE); 46 | 47 | //Установка задержки чтения FLASH памяти до 4-х тактов 48 | FLASH_ACR=FLASH_ACR_DBG_SWEN | FLASH_ACR_DCEN | FLASH_ACR_ICEN | FLASH_ACR_LATENCY_4WS ; 49 | while((FLASH_ACR & 0xf) != FLASH_ACR_LATENCY_4WS ); 50 | 51 | //Подключение внешнего кварцевого резонатора (HSE ON) 52 | SET_BIT(RCC_CR, RCC_CR_HSEON); 53 | while(READ_BIT(RCC_CR, RCC_CR_HSERDY) != (RCC_CR_HSERDY)); 54 | 55 | //Настройка PLL, используемого для SYSCLK домена 56 | //PLLM=6 (значение поля 5), PLLN=85 (значение поля 85), PLLR=2 (значение поля 0) 57 | MODIFY_REG(RCC_PLLCFGR, RCC_PLLCFGR_PLLSRC | RCC_PLLCFGR_PLLM | RCC_PLLCFGR_PLLN | RCC_PLLCFGR_PLLR, 58 | RCC_PLLCFGR_PLLSRC_HSE | 5 < 2 | 3 | void TIM2_Init(void) 4 | { 5 | 6 | SET_BIT(RCC_APB1ENR1, RCC_APB1ENR1_TIM2EN); // Подаем на TIM2 тактовую частоту 7 | TIM2_ARR = 170 - 1; // Загружаем Auto-reload register f = 170 000 000/(TIM2_ARR+1), 1 MHz -> 170 -1 8 | TIM2_CR2 = TIM_CR2_MMS_1; // Выбор мастер режима таймера для возможности тактирования ADC 9 | 10 | } 11 | 12 | -------------------------------------------------------------------------------- /08_ADC_DAC_FIL_DET/Src/vectors.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void start_up(void); 4 | void nmi_handler(void); 5 | void hardfault_handler(void); 6 | void ADC1_IRQHandler(void); 7 | 8 | extern uint32_t _estack; 9 | 10 | /* Таблица векторов прерывания */ 11 | 12 | __attribute__ ((section(".vectors"),used))//Таблицу размещаем в секции .vectors 13 | uint32_t *vectors[] = { 14 | (uint32_t *) &_estack, //Вершина стека 15 | (uint32_t *) start_up, //Обработчик reset (точка входа) 16 | (uint32_t *) nmi_handler, //Обработчик немаскируемого прерывания 17 | (uint32_t *) hardfault_handler, //Обработчик прерывания аппаратной ошибки 18 | 0,0,0,0,0,0,0,0,0,0,0,0, //Окончание блока системных прерываний 19 | 0,0,0,0,0,0,0,0,0,0, //Прерывания 0 - 9 20 | 0,0,0,0,0,0,0,0, //Прерывания 10 -17 21 | (uint32_t *) ADC1_IRQHandler, //Прерывание 18 22 | 0 //Прерывание 19 23 | }; 24 | 25 | /* Обработчик немаскируемого прерывания */ 26 | void nmi_handler(void) 27 | { 28 | for (;;); 29 | } 30 | 31 | /* Обработчик прерывания аппаратной ошибки */ 32 | void hardfault_handler(void) 33 | { 34 | for (;;); 35 | } 36 | -------------------------------------------------------------------------------- /09_ADC_DAC_DET_FIL_DET_EN/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13_ADC_DAC_DET_ENC 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.cdt.managedbuilder.core.genmakebuilder 10 | clean,full,incremental, 11 | 12 | 13 | 14 | 15 | org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder 16 | full,incremental, 17 | 18 | 19 | 20 | 21 | 22 | com.st.stm32cube.ide.mcu.MCUProjectNature 23 | org.eclipse.cdt.core.cnature 24 | com.st.stm32cube.ide.mcu.MCUCubeIdeServicesRevAev2ProjectNature 25 | com.st.stm32cube.ide.mcu.MCUManagedMakefileProjectNature 26 | com.st.stm32cube.ide.mcu.MCUSingleCpuProjectNature 27 | com.st.stm32cube.ide.mcu.MCURootProjectNature 28 | org.eclipse.cdt.managedbuilder.core.managedBuildNature 29 | org.eclipse.cdt.managedbuilder.core.ScannerConfigNature 30 | 31 | 32 | -------------------------------------------------------------------------------- /09_ADC_DAC_DET_FIL_DET_EN/Src/adc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define FD 1000 //Частота дискретизации KHz 5 | #define FLPF 1 //Частота перегиба ФНЧ KHz 6 | extern float R; //Параметр фильтра, зависящий от частоты 7 | 8 | //Вход ADC1 на PA0 9 | void ADC1_init() 10 | { 11 | 12 | //Настройка тактирования ADC 13 | SET_BIT(RCC_CCIPR, 1 << 29 ); // Выбрать системный clock в качестве тактового сигнала для ADC 14 | SET_BIT(RCC_AHB2ENR, 1 << 13 ); // Подать тактовый сигнал на модуль ADC12 15 | SET_BIT(ADC12_COMMON_CCR, 2 << 16 ); // Выбрать в качестве тактового сигнала adc_hclk/2 16 | 17 | //Настройка режима ADC 18 | ADC1_CR = 0; // Сброс всех бит в ADC1_CR (ADEN = 0 для обеспечения конфигурирования) 19 | SET_BIT(ADC1_CR, 1 << 28); // Включить опорное напряжение ADC 20 | // Запуск преобразования от TIM2_TRG0 (канал 11)(биты 5- 11), перезапись разрешена (бит 12) 21 | ADC1_CFGR = (1 << 12)+(1 << 10)+ (11 << 5); 22 | ADC1_SQR1 = (1 << 6); // Выбрать входной канал 1 (PA0) 23 | // ADC1_DIFSEL = 2; // ADC1 канал 1 в дифференциальном режиме 24 | 25 | //Настройка прерывания 26 | ADC1_IER = (1 << 3); // Разрешить прерывание по окончанию преобразования в ADC 27 | SET_BIT(NVIC_ISER0, (1 << 18)); // Разрешить в NVIC прерывание #18 (ADC1) 28 | 29 | /* Установка приоритета n. 30 | Приоритеты задаются в регистрах NVIC_IPRXX (по четыре устройства на регистр см. док.), 31 | Записывается значение n*16 (n 0-15), чем больше значение тем ниже приоритет. 32 | По умолчанию у всех прерываний максимальный приоритет = 0. 33 | */ 34 | 35 | NVIC_IPR4 = 0x00100000; //Установка приоритета 16 для прерывания 18. 36 | 37 | SET_BIT(ADC1_CR, (1 << 0) | (1 << 2));// Включить ADC1 и начать преобразование 38 | SET_BIT(TIM2_CR1, TIM_CR1_CEN); //Запуск TIM2 - cтарт генерации сигнала дискретизации для ADC1 39 | 40 | 41 | } 42 | 43 | 44 | void ADC1_IRQHandler(void) 45 | { 46 | 47 | //Параметр, определяющий полосу пропускания фильтра dF 48 | //L ≈ 5.6 * Fd/FD 49 | static float L = 0.01; 50 | 51 | //Начальные значения переменных фильтра 52 | static float X = 0; 53 | static float V = 0; 54 | 55 | //Параметр интегрирующей цепочки 56 | static float K = 2*M_PI*FLPF/FD; //K = 2PI*f/fd 57 | //Начальные значения переменных детектора 58 | static float U = 0; 59 | float D; 60 | int out; 61 | 62 | //Смещение для ADC и DAC 63 | static int S_ADC = 1910; // Uдел/3.3 * 4096 -> 1.54/3.3 *4096 = 1910 64 | static int S_DAC = 100; 65 | 66 | // Сброс флага переполнения в ADC1 67 | SET_BIT(ADC1_ISR, (1 << 3)); 68 | 69 | //Фильтр 70 | X += (int)ADC1_DR- S_ADC; 71 | V -= X * R; 72 | X += V - X * L; 73 | 74 | //Детектор 75 | D = fabs(X); 76 | U += (D - U) * K; // Интегрирующая цепь ЗЧ 77 | out = U + S_DAC; 78 | 79 | // Ограничитель, предотвращает переполнение DAC при сильном сигнале 80 | if( out > 4000) out = 4000; 81 | 82 | //Запись в DAC 83 | DAC1_DHR12R1 = out; 84 | 85 | } 86 | 87 | -------------------------------------------------------------------------------- /09_ADC_DAC_DET_FIL_DET_EN/Src/dac.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | //Выход DAC1 на PA4 5 | void DAC1_Init(void) 6 | { 7 | 8 | SET_BIT(RCC_AHB2ENR, RCC_AHB2ENR_DAC1EN ); // Подать тактовый сигнал на DAC1 9 | SET_BIT(DAC1_CR, 1); // Включить выход DAC1 10 | DAC1_DHR12R1 = 0; // Записать 0 в регистр данных DAC1 11 | 12 | } 13 | -------------------------------------------------------------------------------- /09_ADC_DAC_DET_FIL_DET_EN/Src/encoder.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define FREQ_MAX 400 // Максимальное значение частоты KHz 5 | #define FREQ_MIN 100 // Минимальное значение частоты KHz 6 | #define FREQ_START 100 // Начальное значение частоты KHz 7 | #define FD 1000 //Частота дискретизации KHz 8 | 9 | uint32_t frequency = FREQ_START; //Глобальная переменная частота фильтра 10 | float R; //Параметр фильтра, зависящий от frequency 11 | 12 | 13 | // Расчет параметра фильтра зависящего от частоты R=(2*Sin(PI*W))^2 14 | 15 | void KHZ_to_R(int fr) 16 | { 17 | R = (2*sin(M_PI*fr/FD)); 18 | R *= R; 19 | } 20 | 21 | 22 | void Encoder_Init(void) 23 | { 24 | 25 | /* Подключение выхода энкодера A (PA6) и B (PA7) к таймеру TIM3 */ 26 | 27 | // Включить PA6 и PA7 на альтерналивную функцию 28 | MODIFY_REG(GPIOA_MODER, GPIO_MODER_MODE7 | GPIO_MODER_MODE6, 2< FREQ_MAX) frequency = FREQ_MIN; 113 | TIM3_CNT = (frequency - FREQ_MIN) *2; 114 | KHZ_to_R(frequency); //Расчет значения R для фильтра 115 | } 116 | -------------------------------------------------------------------------------- /09_ADC_DAC_DET_FIL_DET_EN/Src/gpio.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | void GpioInit(void) 5 | { 6 | SET_BIT(RCC_AHB2ENR, RCC_AHB2ENR_GPIOAEN | RCC_AHB2ENR_GPIOBEN); // Подать тактовый сигнал на GPIOA и GPIOB 7 | MODIFY_REG(GPIOB_MODER, GPIO_MODER_MODE8, 1< 2 | 3 | void GpioInit(void); 4 | void TIM2_Init(void); 5 | void DAC1_Init(void); 6 | void ADC1_init(); 7 | void Encoder_Init(void); 8 | 9 | int main(void) 10 | { 11 | 12 | GpioInit(); //Настройка GPIO 13 | Encoder_Init(); //Настройка энкодера 14 | TIM2_Init(); //Настройка таймера TIM2 15 | DAC1_Init(); //Настройка ЦАП 16 | ADC1_init(); //Настройка и запуск АЦП 17 | 18 | while(1); 19 | } 20 | 21 | -------------------------------------------------------------------------------- /09_ADC_DAC_DET_FIL_DET_EN/Src/stm32f4.ld: -------------------------------------------------------------------------------- 1 | /* Точка входа - функция sturt_up */ 2 | ENTRY(start_up) 3 | 4 | /* 5 | Начальные адреса и размер RAM и FLASH 6 | FLASH также аппаратно отображается в адреса 0x00000000 - 0x00020000 7 | */ 8 | 9 | MEMORY 10 | { 11 | RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 32K 12 | FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 128K 13 | } 14 | 15 | /* Размер таблицы векторов прерывания */ 16 | _size_vector_table = 0x0400; 17 | 18 | /* 19 | Вершина стека 20 | Находится в конце RAM 21 | */ 22 | _estack = ORIGIN(RAM) + LENGTH(RAM); 23 | 24 | 25 | SECTIONS { 26 | 27 | /* Секция векторов прерывания */ 28 | .vectors : { 29 | . = ALIGN(4); 30 | _svector = .; 31 | /*ключевое слово KEEP сохраняет раздел даже если на него нет ссылок*/ 32 | KEEP(*(.vectors)); 33 | . = _svector + _size_vector_table; 34 | . = ALIGN(4); 35 | _evector = .; 36 | } > FLASH 37 | 38 | /* Секция кода программы и констант*/ 39 | .text : { 40 | *(.text*) 41 | *(.rodata*) 42 | } > FLASH 43 | 44 | /* Секция глобальных переменных, инициализированных нулем */ 45 | .bss : { 46 | _sbss = .; 47 | *(.bss*) 48 | *(COMMON) 49 | . = ALIGN(4); 50 | _ebss = .; 51 | } > RAM 52 | 53 | /* Секция глобальных переменных, инициализированных константами */ 54 | .data : { 55 | _sdata_ram = .; 56 | *(.data*) 57 | . = ALIGN(4); 58 | _edata_ram = .; 59 | } > RAM AT > FLASH 60 | 61 | } 62 | 63 | /* Начальный и конечный адрес секции .data во flash памяти */ 64 | _sdata_flash = LOADADDR(.data); 65 | _edata_flash = _sdata_flash + SIZEOF(.data); 66 | 67 | 68 | -------------------------------------------------------------------------------- /09_ADC_DAC_DET_FIL_DET_EN/Src/system_init.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* Константы определены в файле stm32f4.ld */ 4 | extern uint32_t _estack; 5 | extern uint32_t _sdata_ram, _edata_ram; 6 | extern uint32_t _sbss, _ebss; 7 | extern uint32_t _svector, _evector; 8 | extern uint32_t _sdata_flash, _edata_flash; 9 | 10 | void SystemClock_Config(void); 11 | int main(void); 12 | 13 | /* Точка входа */ 14 | void start_up(void) 15 | { 16 | uint32_t *src, *dst; 17 | 18 | /* Копирование данных секции .data из FLASH в RAM */ 19 | src = &_sdata_flash; 20 | dst = &_sdata_ram; 21 | while (dst < &_edata_ram) { 22 | *dst++ = *src++; 23 | } 24 | 25 | /* Запись нулей в область памяти секции .bss */ 26 | dst = &_sbss; 27 | while (dst < &_ebss) { 28 | *dst++ = 0; 29 | } 30 | 31 | /* FPU settings ------------------------------------------------------------*/ 32 | 33 | SCB_CPACR |= ((3UL << (10*2))|(3UL << (11*2))); /* set CP10 and CP11 Full Access */ 34 | 35 | SystemClock_Config(); 36 | main(); 37 | } 38 | 39 | 40 | 41 | void SystemClock_Config(void) 42 | { 43 | 44 | //Включить режим повышения выходного напряжения главного регулятора до 1,28 вольт 45 | CLEAR_BIT(PWR_CR5, PWR_CR5_R1MODE); 46 | 47 | //Установка задержки чтения FLASH памяти до 4-х тактов 48 | FLASH_ACR=FLASH_ACR_DBG_SWEN | FLASH_ACR_DCEN | FLASH_ACR_ICEN | FLASH_ACR_LATENCY_4WS ; 49 | while((FLASH_ACR & 0xf) != FLASH_ACR_LATENCY_4WS ); 50 | 51 | //Подключение внешнего кварцевого резонатора (HSE ON) 52 | SET_BIT(RCC_CR, RCC_CR_HSEON); 53 | while(READ_BIT(RCC_CR, RCC_CR_HSERDY) != (RCC_CR_HSERDY)); 54 | 55 | //Настройка PLL, используемого для SYSCLK домена 56 | //PLLM=6 (значение поля 5), PLLN=85 (значение поля 85), PLLR=2 (значение поля 0) 57 | MODIFY_REG(RCC_PLLCFGR, RCC_PLLCFGR_PLLSRC | RCC_PLLCFGR_PLLM | RCC_PLLCFGR_PLLN | RCC_PLLCFGR_PLLR, 58 | RCC_PLLCFGR_PLLSRC_HSE | 5 < 2 | 3 | void TIM2_Init(void) 4 | { 5 | 6 | SET_BIT(RCC_APB1ENR1, RCC_APB1ENR1_TIM2EN); // Подаем на TIM2 тактовую частоту 7 | TIM2_ARR = 170 - 1; // Загружаем Auto-reload register f = 170 000 000/(TIM2_ARR+1), 1 MHz -> 170 -1 8 | TIM2_CR2 = TIM_CR2_MMS_1; // Выбор мастер режима таймера для возможности тактирования ADC 9 | 10 | } 11 | 12 | -------------------------------------------------------------------------------- /09_ADC_DAC_DET_FIL_DET_EN/Src/vectors.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void start_up(void); 4 | void nmi_handler(void); 5 | void hardfault_handler(void); 6 | void ADC1_IRQHandler(void); 7 | void TIM3_IRQHandler(void); 8 | void EXTI9_5_IRQHandler(void); 9 | 10 | extern uint32_t _estack; 11 | 12 | /* Таблица векторов прерывания */ 13 | 14 | __attribute__ ((section(".vectors"),used))//Таблицу размещаем в секции .vectors 15 | uint32_t *vectors[] = { 16 | (uint32_t *) &_estack, //Вершина стека 17 | (uint32_t *) start_up, //Обработчик reset (точка входа) 18 | (uint32_t *) nmi_handler, //Обработчик немаскируемого прерывания 19 | (uint32_t *) hardfault_handler, //Обработчик прерывания аппаратной ошибки 20 | 0,0,0,0,0,0,0,0,0,0,0,0, //Окончание блока системных прерываний 21 | 0,0,0,0,0,0,0,0,0,0, //Прерывания 0 - 9 22 | 0,0,0,0,0,0,0,0, //Прерывания 10 -17 23 | (uint32_t *) ADC1_IRQHandler, //Прерывание 18 24 | 0, //Прерывание 19 25 | 0,0,0, //Прерывание 20 - 22 26 | (uint32_t *) EXTI9_5_IRQHandler, //23 Обработчик прерывания от EXTI9_5 (Encoder BUT) 27 | 0,0,0,0,0, //Прерывания 24 -28 28 | (uint32_t *) TIM3_IRQHandler, //29 Обработчик прерывания от TIM3 (Encoder) 29 | 0,0,0,0,0,0,0,0,0,0, //Прерывания 30 -39 30 | }; 31 | 32 | /* Обработчик немаскируемого прерывания */ 33 | void nmi_handler(void) 34 | { 35 | for (;;); 36 | } 37 | 38 | /* Обработчик прерывания аппаратной ошибки */ 39 | void hardfault_handler(void) 40 | { 41 | for (;;); 42 | } 43 | -------------------------------------------------------------------------------- /10_ADC_DAC_DET_FIL_DET_EN_OLED/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13_ADC_DAC_DET_ENC_OLED 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.cdt.managedbuilder.core.genmakebuilder 10 | clean,full,incremental, 11 | 12 | 13 | 14 | 15 | org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder 16 | full,incremental, 17 | 18 | 19 | 20 | 21 | 22 | com.st.stm32cube.ide.mcu.MCUProjectNature 23 | org.eclipse.cdt.core.cnature 24 | com.st.stm32cube.ide.mcu.MCUCubeIdeServicesRevAev2ProjectNature 25 | com.st.stm32cube.ide.mcu.MCUManagedMakefileProjectNature 26 | com.st.stm32cube.ide.mcu.MCUSingleCpuProjectNature 27 | com.st.stm32cube.ide.mcu.MCURootProjectNature 28 | org.eclipse.cdt.managedbuilder.core.managedBuildNature 29 | org.eclipse.cdt.managedbuilder.core.ScannerConfigNature 30 | 31 | 32 | -------------------------------------------------------------------------------- /10_ADC_DAC_DET_FIL_DET_EN_OLED/Src/adc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define FD 1000 //Частота дискретизации KHz 5 | #define FLPF 1 //Частота перегиба ФНЧ KHz 6 | float R; //Параметр фильтра, зависящий от frequency 7 | 8 | //Вход ADC1 на PA0 9 | void ADC1_init() 10 | { 11 | 12 | //Настройка тактирования ADC 13 | SET_BIT(RCC_CCIPR, 1 << 29 ); // Выбрать системный clock в качестве тактового сигнала для ADC 14 | SET_BIT(RCC_AHB2ENR, 1 << 13 ); // Подать тактовый сигнал на модуль ADC12 15 | SET_BIT(ADC12_COMMON_CCR, 2 << 16 ); // Выбрать в качестве тактового сигнала adc_hclk/2 16 | 17 | //Настройка режима ADC 18 | ADC1_CR = 0; // Сброс всех бит в ADC1_CR (ADEN = 0 для обеспечения конфигурирования) 19 | SET_BIT(ADC1_CR, 1 << 28); // Включить опорное напряжение ADC 20 | 21 | // Запуск преобразования от TIM2_TRG0 (канал 11)(биты 5- 11), перезапись разрешена (бит 12) 22 | ADC1_CFGR = (1 << 12)+(1 << 10)+ (11 << 5); 23 | ADC1_SQR1 = (1 << 6); // Выбрать входной канал 1 (PA0) 24 | 25 | //Настройка прерывания 26 | ADC1_IER = (1 << 3); // Разрешить прерывание по окончанию преобразования в ADC 27 | SET_BIT(NVIC_ISER0, (1 << 18)); // Разрешить в NVIC прерывание #18 (ADC1) 28 | 29 | /* Установка приоритета n. 30 | Приоритеты задаются в регистрах NVIC_IPRXX (по четыре устройства на регистр см. док.), 31 | Записывается значение n*16 (n 0-15), чем больше значение тем ниже приоритет. 32 | По умолчанию у всех прерываний максимальный приоритет = 0. 33 | */ 34 | 35 | NVIC_IPR4 = 0x00100000; //Установка приоритета 16 для прерывания 18. 36 | 37 | SET_BIT(ADC1_CR, (1 << 0) | (1 << 2));// Включить ADC1 и начать преобразование 38 | SET_BIT(TIM2_CR1, TIM_CR1_CEN); //Запуск TIM2 - cтарт генерации сигнала дискретизации для ADC1 39 | 40 | } 41 | 42 | // Расчет параметра фильтра зависящего от частоты R=(2*Sin(PI*W))^2 43 | void KHZ_to_R(int fr) 44 | { 45 | R = (2*sin(M_PI*(0.996*fr)/FD)); 46 | R *= R; 47 | } 48 | 49 | 50 | 51 | void ADC1_IRQHandler(void) 52 | { 53 | 54 | //Параметр, определяющий полосу пропускания фильтра dF 55 | //L ≈ 5.6 * Fd/FD 56 | static float L = 0.005; 57 | 58 | //Начальные значения переменных фильтра 59 | static float X = 0; 60 | static float V = 0; 61 | 62 | //Параметр интегрирующей цепочки 63 | static float K = 2*M_PI*FLPF/FD; //K = 2PI*f/fd 64 | //Начальные значения переменных детектора 65 | static float U = 0; 66 | float D; 67 | int out; 68 | 69 | //Смещение для ADC и DAC 70 | static int S_ADC = 1910; // Uдел/3.3 * 4096 -> 1.54/3.3 *4096 = 1910 71 | static int S_DAC = 800; 72 | 73 | 74 | // Сброс флага переполнения в ADC1 75 | SET_BIT(ADC1_ISR, (1 << 3)); 76 | 77 | //Фильтр 78 | X += (int)ADC1_DR- S_ADC; 79 | V -= X * R; 80 | X += V - X * L; 81 | 82 | //Детектор 83 | D = fabs(X); 84 | U += (D - U) * K; // Интегрирующая цепь ЗЧ 85 | out = U + S_DAC; 86 | 87 | // Ограничитель, предотвращает переполнение DAC при сильном сигнале 88 | if( out > 4000) out = 4000; 89 | 90 | //Запись в DAC 91 | DAC1_DHR12R1 = out; 92 | 93 | } 94 | 95 | -------------------------------------------------------------------------------- /10_ADC_DAC_DET_FIL_DET_EN_OLED/Src/dac.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | //Выход DAC1 на PA4 5 | void DAC1_Init(void) 6 | { 7 | 8 | SET_BIT(RCC_AHB2ENR, RCC_AHB2ENR_DAC1EN ); // Подать тактовый сигнал на DAC1 9 | SET_BIT(DAC1_CR, 1); // Включить выход DAC1 10 | DAC1_DHR12R1 = 0; // Записать 0 в регистр данных DAC1 11 | 12 | } 13 | -------------------------------------------------------------------------------- /10_ADC_DAC_DET_FIL_DET_EN_OLED/Src/encoder.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define FREQ_MAX 400 // Максимальное значение частоты KHz 7 | #define FREQ_MIN 100 // Минимальное значение частоты KHz 8 | #define FREQ_START 100 // Начальное значение частоты KHz 9 | 10 | void print(uint8_t x,uint8_t y,char *str); 11 | 12 | uint32_t frequency = FREQ_START; //Центральная частота полосы пропускания фильтра 13 | 14 | void KHZ_to_R(int fr); 15 | 16 | void FreqPrint() 17 | { 18 | static char ds[10] = " "; 19 | if( frequency > 9999 ) return; 20 | itoa(frequency, ds + 4 , 10); 21 | print(48,1,ds + strlen(ds + 4)); 22 | } 23 | 24 | void Encoder_Init(void) 25 | { 26 | 27 | /* Подключение выхода энкодера A (PA6) и B (PA7) к таймеру TIM3 */ 28 | 29 | // Включить PA6 и PA7 на альтерналивную функцию 30 | MODIFY_REG(GPIOA_MODER, GPIO_MODER_MODE7 | GPIO_MODER_MODE6, 2< FREQ_MAX) frequency = FREQ_MIN; 120 | TIM3_CNT = (frequency - FREQ_MIN) *2; 121 | KHZ_to_R(frequency); //Расчет значения R для фильтра 122 | FreqPrint(); 123 | } 124 | -------------------------------------------------------------------------------- /10_ADC_DAC_DET_FIL_DET_EN_OLED/Src/gpio.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | void GpioInit(void) 5 | { 6 | SET_BIT(RCC_AHB2ENR, RCC_AHB2ENR_GPIOAEN | RCC_AHB2ENR_GPIOBEN); // Подать тактовый сигнал на GPIOA и GPIOB 7 | MODIFY_REG(GPIOB_MODER, GPIO_MODER_MODE8, 1< 2 | 3 | void GpioInit(void); 4 | void OLED_Init(void); 5 | void print(uint8_t x,uint8_t y,char *str); 6 | 7 | 8 | void TIM2_Init(void); 9 | void DAC1_Init(void); 10 | void ADC1_init(); 11 | void Encoder_Init(void); 12 | 13 | int main(void) 14 | { 15 | 16 | GpioInit(); //Настройка GPIO 17 | 18 | OLED_Init(); //Настройка OLED 19 | 20 | print(0,1,"Freq : KHz"); 21 | 22 | Encoder_Init(); //Настройка энкодера 23 | TIM2_Init(); //Настройка таймера TIM2 24 | DAC1_Init(); //Настройка ЦАП 25 | ADC1_init(); //Настройка и запуск АЦП 26 | 27 | while(1); 28 | 29 | } 30 | 31 | -------------------------------------------------------------------------------- /10_ADC_DAC_DET_FIL_DET_EN_OLED/Src/stm32f4.ld: -------------------------------------------------------------------------------- 1 | /* Точка входа - функция sturt_up */ 2 | ENTRY(start_up) 3 | 4 | /* 5 | Начальные адреса и размер RAM и FLASH 6 | FLASH также аппаратно отображается в адреса 0x00000000 - 0x00020000 7 | */ 8 | 9 | MEMORY 10 | { 11 | RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 32K 12 | FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 128K 13 | } 14 | 15 | /* Размер таблицы векторов прерывания */ 16 | _size_vector_table = 0x0400; 17 | 18 | /* 19 | Вершина стека 20 | Находится в конце RAM 21 | */ 22 | _estack = ORIGIN(RAM) + LENGTH(RAM); 23 | 24 | 25 | SECTIONS { 26 | 27 | /* Секция векторов прерывания */ 28 | .vectors : { 29 | . = ALIGN(4); 30 | _svector = .; 31 | /*ключевое слово KEEP сохраняет раздел даже если на него нет ссылок*/ 32 | KEEP(*(.vectors)); 33 | . = _svector + _size_vector_table; 34 | . = ALIGN(4); 35 | _evector = .; 36 | } > FLASH 37 | 38 | /* Секция кода программы и констант*/ 39 | .text : { 40 | *(.text*) 41 | *(.rodata*) 42 | } > FLASH 43 | 44 | /* Секция глобальных переменных, инициализированных нулем */ 45 | .bss : { 46 | _sbss = .; 47 | *(.bss*) 48 | *(COMMON) 49 | . = ALIGN(4); 50 | _ebss = .; 51 | } > RAM 52 | 53 | /* Секция глобальных переменных, инициализированных константами */ 54 | .data : { 55 | _sdata_ram = .; 56 | *(.data*) 57 | . = ALIGN(4); 58 | _edata_ram = .; 59 | } > RAM AT > FLASH 60 | 61 | } 62 | 63 | /* Начальный и конечный адрес секции .data во flash памяти */ 64 | _sdata_flash = LOADADDR(.data); 65 | _edata_flash = _sdata_flash + SIZEOF(.data); 66 | 67 | 68 | -------------------------------------------------------------------------------- /10_ADC_DAC_DET_FIL_DET_EN_OLED/Src/system_init.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* Константы определены в файле stm32f4.ld */ 4 | extern uint32_t _estack; 5 | extern uint32_t _sdata_ram, _edata_ram; 6 | extern uint32_t _sbss, _ebss; 7 | extern uint32_t _svector, _evector; 8 | extern uint32_t _sdata_flash, _edata_flash; 9 | 10 | void SystemClock_Config(void); 11 | int main(void); 12 | 13 | /* Точка входа */ 14 | void start_up(void) 15 | { 16 | uint32_t *src, *dst; 17 | 18 | /* Копирование данных секции .data из FLASH в RAM */ 19 | src = &_sdata_flash; 20 | dst = &_sdata_ram; 21 | while (dst < &_edata_ram) { 22 | *dst++ = *src++; 23 | } 24 | 25 | /* Запись нулей в область памяти секции .bss */ 26 | dst = &_sbss; 27 | while (dst < &_ebss) { 28 | *dst++ = 0; 29 | } 30 | 31 | /* FPU settings ------------------------------------------------------------*/ 32 | 33 | SCB_CPACR |= ((3UL << (10*2))|(3UL << (11*2))); /* set CP10 and CP11 Full Access */ 34 | 35 | SystemClock_Config(); 36 | main(); 37 | } 38 | 39 | 40 | 41 | void SystemClock_Config(void) 42 | { 43 | 44 | //Включить режим повышения выходного напряжения главного регулятора до 1,28 вольт 45 | CLEAR_BIT(PWR_CR5, PWR_CR5_R1MODE); 46 | 47 | //Установка задержки чтения FLASH памяти до 4-х тактов 48 | FLASH_ACR=FLASH_ACR_DBG_SWEN | FLASH_ACR_DCEN | FLASH_ACR_ICEN | FLASH_ACR_LATENCY_4WS ; 49 | while((FLASH_ACR & 0xf) != FLASH_ACR_LATENCY_4WS ); 50 | 51 | //Подключение внешнего кварцевого резонатора (HSE ON) 52 | SET_BIT(RCC_CR, RCC_CR_HSEON); 53 | while(READ_BIT(RCC_CR, RCC_CR_HSERDY) != (RCC_CR_HSERDY)); 54 | 55 | //Настройка PLL, используемого для SYSCLK домена 56 | //PLLM=6 (значение поля 5), PLLN=85 (значение поля 85), PLLR=2 (значение поля 0) 57 | MODIFY_REG(RCC_PLLCFGR, RCC_PLLCFGR_PLLSRC | RCC_PLLCFGR_PLLM | RCC_PLLCFGR_PLLN | RCC_PLLCFGR_PLLR, 58 | RCC_PLLCFGR_PLLSRC_HSE | 5 < 2 | 3 | void TIM2_Init(void) 4 | { 5 | 6 | SET_BIT(RCC_APB1ENR1, RCC_APB1ENR1_TIM2EN); // Подаем на TIM2 тактовую частоту 7 | TIM2_ARR = 170 - 1; // Загружаем Auto-reload register f = 170 000 000/(TIM2_ARR+1), 1 MHz -> 170 -1 8 | TIM2_CR2 = TIM_CR2_MMS_1; // Выбор мастер режима таймера для возможности тактирования ADC 9 | 10 | } 11 | 12 | -------------------------------------------------------------------------------- /10_ADC_DAC_DET_FIL_DET_EN_OLED/Src/vectors.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void start_up(void); 4 | void nmi_handler(void); 5 | void hardfault_handler(void); 6 | void ADC1_IRQHandler(void); 7 | void TIM3_IRQHandler(void); 8 | void EXTI9_5_IRQHandler(void); 9 | void DMA1_CH3_IRQHandler(); 10 | 11 | 12 | extern uint32_t _estack; 13 | 14 | /* Таблица векторов прерывания */ 15 | 16 | __attribute__ ((section(".vectors"),used))//Таблицу размещаем в секции .vectors 17 | uint32_t *vectors[] = { 18 | (uint32_t *) &_estack, //Вершина стека 19 | (uint32_t *) start_up, //Обработчик reset (точка входа) 20 | (uint32_t *) nmi_handler, //Обработчик немаскируемого прерывания 21 | (uint32_t *) hardfault_handler, //Обработчик прерывания аппаратной ошибки 22 | 0,0,0,0,0,0,0,0,0,0,0,0, //Окончание блока системных прерываний 23 | 0,0,0,0,0,0,0,0,0,0, //Прерывания 0 - 9 24 | 0,0,0, //Прерывания 10 -12 25 | (uint32_t *) DMA1_CH3_IRQHandler, //Прерывание 13, OLED 26 | 0,0,0,0, //Прерывания 14 -17 27 | (uint32_t *) ADC1_IRQHandler, //Прерывание ADC1_IRQHandler 28 | 0, //Прерывание 19 29 | 0,0,0, //Прерывание 20 - 22 30 | (uint32_t *) EXTI9_5_IRQHandler, //23 Обработчик прерывания от EXTI9_5 (Encoder BUT) 31 | 0,0,0,0,0, //Прерывания 24 -28 32 | (uint32_t *) TIM3_IRQHandler //29 Обработчик прерывания от TIM3 (Encoder) 33 | }; 34 | 35 | /* Обработчик немаскируемого прерывания */ 36 | void nmi_handler(void) 37 | { 38 | for (;;); 39 | } 40 | 41 | /* Обработчик прерывания аппаратной ошибки */ 42 | void hardfault_handler(void) 43 | { 44 | for (;;); 45 | } 46 | -------------------------------------------------------------------------------- /11_SIMPLE_RADIO/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11_SIMPLE_RADIO 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.cdt.managedbuilder.core.genmakebuilder 10 | clean,full,incremental, 11 | 12 | 13 | 14 | 15 | org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder 16 | full,incremental, 17 | 18 | 19 | 20 | 21 | 22 | com.st.stm32cube.ide.mcu.MCUProjectNature 23 | org.eclipse.cdt.core.cnature 24 | com.st.stm32cube.ide.mcu.MCUCubeIdeServicesRevAev2ProjectNature 25 | com.st.stm32cube.ide.mcu.MCUManagedMakefileProjectNature 26 | com.st.stm32cube.ide.mcu.MCUSingleCpuProjectNature 27 | com.st.stm32cube.ide.mcu.MCURootProjectNature 28 | org.eclipse.cdt.managedbuilder.core.managedBuildNature 29 | org.eclipse.cdt.managedbuilder.core.ScannerConfigNature 30 | 31 | 32 | -------------------------------------------------------------------------------- /11_SIMPLE_RADIO/Src/adc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define FD 700 //Частота дискретизации KHz 5 | #define FLPF 2 //Частота перегиба ФНЧ KHz 6 | #define FAGC 0.001 //Частота перегиба АРУ KHz 7 | float R; //Параметр фильтра, зависящий от frequency 8 | 9 | 10 | //Таймер, задающий частоту дискретизации ADC1 11 | void TIM2_Init(void) 12 | { 13 | 14 | SET_BIT(RCC_APB1ENR1, RCC_APB1ENR1_TIM2EN); // Подаем на TIM2 тактовую частоту 15 | TIM2_ARR = 170000/FD - 1; // Загружаем Auto-reload register f = 170 000 000/(TIM2_ARR+1), 1 MHz -> 170 -1 16 | TIM2_CR2 = TIM_CR2_MMS_1; // Выбор мастер режима таймера для возможности тактирования ADC 17 | 18 | } 19 | 20 | //Вход ADC1 на PA0 21 | void ADC1_init() 22 | { 23 | 24 | //Настройка тактирования ADC 25 | SET_BIT(RCC_CCIPR, 1 << 29 ); // Выбрать системный clock в качестве тактового сигнала для ADC 26 | SET_BIT(RCC_AHB2ENR, 1 << 13 ); // Подать тактовый сигнал на модуль ADC12 27 | SET_BIT(ADC12_COMMON_CCR, 2 << 16 ); // Выбрать в качестве тактового сигнала adc_hclk/2 28 | 29 | //Настройка режима ADC 30 | ADC1_CR = 0; // Сброс всех бит в ADC1_CR (ADEN = 0 для обеспечения конфигурирования) 31 | SET_BIT(ADC1_CR, 1 << 28); // Включить опорное напряжение ADC 32 | 33 | // Запуск преобразования от TIM2_TRG0 (канал 11)(биты 5- 11), перезапись разрешена (бит 12) 34 | ADC1_CFGR = (1 << 12)+(1 << 10)+ (11 << 5); 35 | ADC1_SQR1 = (1 << 6); // Выбрать входной канал 1 (PA0) 36 | 37 | //Настройка прерывания 38 | ADC1_IER = (1 << 3); // Разрешить прерывание по окончанию преобразования в ADC 39 | SET_BIT(NVIC_ISER0, (1 << 18)); // Разрешить в NVIC прерывание #18 (ADC1) 40 | 41 | /* Установка приоритета n. 42 | Приоритеты задаются в регистрах NVIC_IPRXX (по четыре устройства на регистр см. док.), 43 | Записывается значение n*16 (n 0-15), чем больше значение тем ниже приоритет. 44 | По умолчанию у всех прерываний максимальный приоритет = 0. 45 | */ 46 | 47 | NVIC_IPR4 = 0x00100000; //Установка приоритета 1 для прерывания 18. 48 | 49 | SET_BIT(ADC1_CR, (1 << 0) | (1 << 2));// Включить ADC1 и начать преобразование 50 | SET_BIT(TIM2_CR1, TIM_CR1_CEN); //Запуск TIM2 - cтарт генерации сигнала дискретизации для ADC1 51 | 52 | } 53 | 54 | // Расчет параметра фильтра зависящего от частоты R=(2*Sin(PI*W))^2 55 | void KHZ_to_R(int fr) 56 | { 57 | R = (2*sin(M_PI*(0.996*fr)/FD)); 58 | R *= R; 59 | } 60 | 61 | //Обработка отсчета от ADC1 62 | void ADC1_IRQHandler(void) 63 | { 64 | 65 | //Параметр, определяющий полосу пропускания фильтра dF 66 | //L ≈ 5.6 * Fd/FD 67 | static float L = 0.005; 68 | 69 | //Начальные значения переменных фильтра 70 | static float X = 0; 71 | static float V = 0; 72 | 73 | //Параметр интегрирующей цепочки 74 | static float K1 = 2*M_PI*FLPF/FD; //ФНЧ K = 2PI*f/fd 75 | static float K2 = 2*M_PI*FAGC/FD; //АРУ 76 | 77 | //Начальные значения переменных детектора 78 | static float U1 = 0; 79 | static float U2 = 0; 80 | static float AGCT = 1000; 81 | 82 | //Смещение для ADC и DAC 83 | static int S_ADC = 1975; // Uдел/3.3 * 4096 -> 1.586/3.29 *4096 = 1910 84 | static int S_DAC = 800; 85 | 86 | float D; 87 | int OUT; 88 | 89 | // Сброс флага переполнения в ADC1 90 | SET_BIT(ADC1_ISR, (1 << 3)); 91 | 92 | //Фильтр 93 | X += (int)ADC1_DR- S_ADC; 94 | V -= X * R; 95 | X += V - X * L; 96 | 97 | //Детектор 98 | D = fabs(X); 99 | U1 += (D - U1) * K1; // Интегрирующая цепь ФНЧ 100 | OUT = U1; 101 | 102 | //АРУ 103 | U2 += (D - U2) * K2; // Интегрирующая цепь АРУ 104 | if( U2 > AGCT) 105 | OUT = U1*(AGCT/U2); 106 | 107 | OUT += S_DAC; 108 | 109 | // Ограничитель, предотвращает переполнение DAC при сильном сигнале 110 | if( OUT > 4000) OUT = 4000; 111 | 112 | //Запись в DAC 113 | DAC1_DHR12R1 = OUT; 114 | 115 | } 116 | 117 | -------------------------------------------------------------------------------- /11_SIMPLE_RADIO/Src/dac.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | //Выход DAC1 на PA4 5 | void DAC1_Init(void) 6 | { 7 | 8 | SET_BIT(RCC_AHB2ENR, RCC_AHB2ENR_DAC1EN ); // Подать тактовый сигнал на DAC1 9 | SET_BIT(DAC1_CR, 1); // Включить выход DAC1 10 | DAC1_DHR12R1 = 0; // Записать 0 в регистр данных DAC1 11 | 12 | } 13 | -------------------------------------------------------------------------------- /11_SIMPLE_RADIO/Src/encoder.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define FREQ_MAX 280 // Максимальное значение частоты KHz 7 | #define FREQ_MIN 150 // Минимальное значение частоты KHz 8 | #define FREQ_START 150 // Начальное значение частоты KHz 9 | 10 | void print(uint8_t x,uint8_t y,char *str); 11 | 12 | uint32_t frequency = FREQ_START; //Центральная частота полосы пропускания фильтра 13 | 14 | void KHZ_to_R(int fr); 15 | 16 | void FreqPrint() 17 | { 18 | static char ds[10] = " "; 19 | if( frequency > 9999 ) return; 20 | itoa(frequency, ds + 4 , 10); 21 | print(48,1,ds + strlen(ds + 4)); 22 | } 23 | 24 | void Encoder_Init(void) 25 | { 26 | 27 | /* Подключение выхода энкодера A (PA6) и B (PA7) к таймеру TIM3 */ 28 | 29 | // Включить PA6 и PA7 на альтерналивную функцию 30 | MODIFY_REG(GPIOA_MODER, GPIO_MODER_MODE7 | GPIO_MODER_MODE6, 2< FREQ_MAX) frequency = FREQ_MIN; 119 | TIM3_CNT = (frequency - FREQ_MIN) *2; 120 | KHZ_to_R(frequency); //Расчет значения R для фильтра 121 | FreqPrint(); 122 | } 123 | -------------------------------------------------------------------------------- /11_SIMPLE_RADIO/Src/gpio.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | void GpioInit(void) 5 | { 6 | SET_BIT(RCC_AHB2ENR, RCC_AHB2ENR_GPIOAEN | RCC_AHB2ENR_GPIOBEN); // Подать тактовый сигнал на GPIOA и GPIOB 7 | MODIFY_REG(GPIOB_MODER, GPIO_MODER_MODE8, 1< 2 | 3 | void GpioInit(void); 4 | void OLED_Init(void); 5 | void print(uint8_t x,uint8_t y,char *str); 6 | 7 | 8 | void TIM2_Init(void); 9 | void DAC1_Init(void); 10 | void ADC1_init(); 11 | void Encoder_Init(void); 12 | 13 | int main(void) 14 | { 15 | 16 | GpioInit(); //Настройка GPIO 17 | 18 | OLED_Init(); //Настройка OLED 19 | 20 | print(0,1,"Freq : KHz"); 21 | 22 | Encoder_Init(); //Настройка энкодера 23 | TIM2_Init(); //Настройка таймера TIM2 24 | DAC1_Init(); //Настройка ЦАП 25 | ADC1_init(); //Настройка и запуск АЦП 26 | 27 | while(1); 28 | 29 | } 30 | 31 | -------------------------------------------------------------------------------- /11_SIMPLE_RADIO/Src/stm32f4.ld: -------------------------------------------------------------------------------- 1 | /* Точка входа - функция sturt_up */ 2 | ENTRY(start_up) 3 | 4 | /* 5 | Начальные адреса и размер RAM и FLASH 6 | FLASH также аппаратно отображается в адреса 0x00000000 - 0x00020000 7 | */ 8 | 9 | MEMORY 10 | { 11 | RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 32K 12 | FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 128K 13 | } 14 | 15 | /* Размер таблицы векторов прерывания */ 16 | _size_vector_table = 0x0400; 17 | 18 | /* 19 | Вершина стека 20 | Находится в конце RAM 21 | */ 22 | _estack = ORIGIN(RAM) + LENGTH(RAM); 23 | 24 | 25 | SECTIONS { 26 | 27 | /* Секция векторов прерывания */ 28 | .vectors : { 29 | . = ALIGN(4); 30 | _svector = .; 31 | /*ключевое слово KEEP сохраняет раздел даже если на него нет ссылок*/ 32 | KEEP(*(.vectors)); 33 | . = _svector + _size_vector_table; 34 | . = ALIGN(4); 35 | _evector = .; 36 | } > FLASH 37 | 38 | /* Секция кода программы и констант*/ 39 | .text : { 40 | *(.text*) 41 | *(.rodata*) 42 | } > FLASH 43 | 44 | /* Секция глобальных переменных, инициализированных нулем */ 45 | .bss : { 46 | _sbss = .; 47 | *(.bss*) 48 | *(COMMON) 49 | . = ALIGN(4); 50 | _ebss = .; 51 | } > RAM 52 | 53 | /* Секция глобальных переменных, инициализированных константами */ 54 | .data : { 55 | _sdata_ram = .; 56 | *(.data*) 57 | . = ALIGN(4); 58 | _edata_ram = .; 59 | } > RAM AT > FLASH 60 | 61 | } 62 | 63 | /* Начальный и конечный адрес секции .data во flash памяти */ 64 | _sdata_flash = LOADADDR(.data); 65 | _edata_flash = _sdata_flash + SIZEOF(.data); 66 | 67 | 68 | -------------------------------------------------------------------------------- /11_SIMPLE_RADIO/Src/system_init.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* Константы определены в файле stm32f4.ld */ 4 | extern uint32_t _estack; 5 | extern uint32_t _sdata_ram, _edata_ram; 6 | extern uint32_t _sbss, _ebss; 7 | extern uint32_t _svector, _evector; 8 | extern uint32_t _sdata_flash, _edata_flash; 9 | 10 | void SystemClock_Config(void); 11 | int main(void); 12 | 13 | /* Точка входа */ 14 | void start_up(void) 15 | { 16 | uint32_t *src, *dst; 17 | 18 | /* Копирование данных секции .data из FLASH в RAM */ 19 | src = &_sdata_flash; 20 | dst = &_sdata_ram; 21 | while (dst < &_edata_ram) { 22 | *dst++ = *src++; 23 | } 24 | 25 | /* Запись нулей в область памяти секции .bss */ 26 | dst = &_sbss; 27 | while (dst < &_ebss) { 28 | *dst++ = 0; 29 | } 30 | 31 | /* FPU settings ------------------------------------------------------------*/ 32 | 33 | SCB_CPACR |= ((3UL << (10*2))|(3UL << (11*2))); /* set CP10 and CP11 Full Access */ 34 | 35 | SystemClock_Config(); 36 | main(); 37 | } 38 | 39 | 40 | 41 | void SystemClock_Config(void) 42 | { 43 | 44 | //Включить режим повышения выходного напряжения главного регулятора до 1,28 вольт 45 | CLEAR_BIT(PWR_CR5, PWR_CR5_R1MODE); 46 | 47 | //Установка задержки чтения FLASH памяти до 4-х тактов 48 | FLASH_ACR=FLASH_ACR_DBG_SWEN | FLASH_ACR_DCEN | FLASH_ACR_ICEN | FLASH_ACR_LATENCY_4WS ; 49 | while((FLASH_ACR & 0xf) != FLASH_ACR_LATENCY_4WS ); 50 | 51 | //Подключение внешнего кварцевого резонатора (HSE ON) 52 | SET_BIT(RCC_CR, RCC_CR_HSEON); 53 | while(READ_BIT(RCC_CR, RCC_CR_HSERDY) != (RCC_CR_HSERDY)); 54 | 55 | //Настройка PLL, используемого для SYSCLK домена 56 | //PLLM=6 (значение поля 5), PLLN=85 (значение поля 85), PLLR=2 (значение поля 0) 57 | MODIFY_REG(RCC_PLLCFGR, RCC_PLLCFGR_PLLSRC | RCC_PLLCFGR_PLLM | RCC_PLLCFGR_PLLN | RCC_PLLCFGR_PLLR, 58 | RCC_PLLCFGR_PLLSRC_HSE | 5 < 2 | 3 | void start_up(void); 4 | void nmi_handler(void); 5 | void hardfault_handler(void); 6 | void ADC1_IRQHandler(void); 7 | void TIM3_IRQHandler(void); 8 | void EXTI9_5_IRQHandler(void); 9 | void DMA1_CH3_IRQHandler(); 10 | 11 | 12 | extern uint32_t _estack; 13 | 14 | /* Таблица векторов прерывания */ 15 | 16 | __attribute__ ((section(".vectors"),used))//Таблицу размещаем в секции .vectors 17 | uint32_t *vectors[] = { 18 | (uint32_t *) &_estack, //Вершина стека 19 | (uint32_t *) start_up, //Обработчик reset (точка входа) 20 | (uint32_t *) nmi_handler, //Обработчик немаскируемого прерывания 21 | (uint32_t *) hardfault_handler, //Обработчик прерывания аппаратной ошибки 22 | 0,0,0,0,0,0,0,0,0,0,0,0, //Окончание блока системных прерываний 23 | 0,0,0,0,0,0,0,0,0,0, //Прерывания 0 - 9 24 | 0,0,0, //Прерывания 10 -12 25 | (uint32_t *) DMA1_CH3_IRQHandler, //Прерывание 13, OLED 26 | 0,0,0,0, //Прерывания 14 -17 27 | (uint32_t *) ADC1_IRQHandler, //Прерывание ADC1_IRQHandler 28 | 0, //Прерывание 19 29 | 0,0,0, //Прерывание 20 - 22 30 | (uint32_t *) EXTI9_5_IRQHandler, //23 Обработчик прерывания от EXTI9_5 (Encoder BUT) 31 | 0,0,0,0,0, //Прерывания 24 -28 32 | (uint32_t *) TIM3_IRQHandler //29 Обработчик прерывания от TIM3 (Encoder) 33 | }; 34 | 35 | /* Обработчик немаскируемого прерывания */ 36 | void nmi_handler(void) 37 | { 38 | for (;;); 39 | } 40 | 41 | /* Обработчик прерывания аппаратной ошибки */ 42 | void hardfault_handler(void) 43 | { 44 | for (;;); 45 | } 46 | -------------------------------------------------------------------------------- /12_SIMPLE_RADIO_DMA/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | 12_SIMPLE_RADIO_DMA 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.cdt.managedbuilder.core.genmakebuilder 10 | clean,full,incremental, 11 | 12 | 13 | 14 | 15 | org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder 16 | full,incremental, 17 | 18 | 19 | 20 | 21 | 22 | com.st.stm32cube.ide.mcu.MCUProjectNature 23 | org.eclipse.cdt.core.cnature 24 | com.st.stm32cube.ide.mcu.MCUCubeIdeServicesRevAev2ProjectNature 25 | com.st.stm32cube.ide.mcu.MCUManagedMakefileProjectNature 26 | com.st.stm32cube.ide.mcu.MCUSingleCpuProjectNature 27 | com.st.stm32cube.ide.mcu.MCURootProjectNature 28 | org.eclipse.cdt.managedbuilder.core.managedBuildNature 29 | org.eclipse.cdt.managedbuilder.core.ScannerConfigNature 30 | 31 | 32 | -------------------------------------------------------------------------------- /12_SIMPLE_RADIO_DMA/Src/adc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define WAVEFORM_SAMPLES_SIZE 64 //Длина буфера ADC (не забудь поменять в dsp.s) 5 | uint16_t Waveform_ADC[WAVEFORM_SAMPLES_SIZE*2]; //Два буфера 6 | 7 | #define FD 1600 //Частота дискретизации KHz 8 | #define FLPF 2 //Частота перегиба ФНЧ KHz 9 | #define FAGC 0.001 //Частота перегиба АРУ KHz 10 | float R; //Параметр фильтра, зависящий от frequency 11 | 12 | 13 | //Таймер, задающий частоту дискретизации ADC1 14 | void TIM2_Init(void) 15 | { 16 | 17 | SET_BIT(RCC_APB1ENR1, RCC_APB1ENR1_TIM2EN); // Подаем на TIM2 тактовую частоту 18 | TIM2_ARR = 170000/FD - 1; // Загружаем Auto-reload register f = 170 000 000/(TIM2_ARR+1), 1 MHz -> 170 -1 19 | TIM2_CR2 = TIM_CR2_MMS_1; // Выбор мастер режима таймера для возможности тактирования ADC 20 | 21 | } 22 | 23 | //Вход ADC1 на PA0 24 | void ADC1_init() 25 | { 26 | 27 | //Настройка тактирования ADC 28 | SET_BIT(RCC_CCIPR, 1 << 29 ); // Выбрать системный clock в качестве тактового сигнала для ADC 29 | SET_BIT(RCC_AHB2ENR, 1 << 13 ); // Подать тактовый сигнал на модуль ADC12 30 | SET_BIT(ADC12_COMMON_CCR, 2 << 16 ); // Выбрать в качестве тактового сигнала adc_hclk/2 31 | 32 | //Настройка режима ADC 33 | ADC1_CR = 0; // Сброс всех бит в ADC1_CR (ADEN = 0 для обеспечения конфигурирования) 34 | SET_BIT(ADC1_CR, 1 << 28); // Включить опорное напряжение ADC 35 | 36 | // Start calibration sequence 37 | ADC1_CR |= (1 << 31); 38 | while(ADC1_CR & (1 << 31)); // wait for calibration to finish 39 | 40 | // Запуск преобразования от TIM2_TRG0 (канал 11)(биты 5- 11), перезапись разрешена (бит 12) 41 | ADC1_CFGR = (1 << 12)+(1 << 10)+ (11 << 5); 42 | ADC1_SQR1 = (1 << 6); // Выбрать входной канал 1 (PA0) 43 | 44 | /* ADC1 DMA Init */ 45 | 46 | SET_BIT(RCC_AHB1ENR, RCC_AHB1ENR_DMAMUX1EN); //Подача тактового сигнала на DMAMUX1 47 | SET_BIT(RCC_AHB1ENR, RCC_AHB1ENR_DMA1EN); //Подача тактового сигнала на DMA1 48 | 49 | MODIFY_REG(DMAMUX1_Channel3_CCR, DMAMUX_CxCR_DMAREQ_ID, 5); //DMAMUX request from line 5 (ADC1) 50 | MODIFY_REG(DMA1_Channel4_CCR, DMA_CCR_DIR | DMA_CCR_MEM2MEM, 0); ////DMA_DIRECTION_PERIPH_TO_MEMORY 51 | MODIFY_REG(DMA1_Channel4_CCR, DMA_CCR_PL, DMA_CCR_PL_1); //DMA_SetChannelPriorityLevel 52 | MODIFY_REG(DMA1_Channel4_CCR, DMA_CCR_CIRC, DMA_CCR_CIRC); //DMA_SetMode CIRC 53 | MODIFY_REG(DMA1_Channel4_CCR, DMA_CCR_PINC, 0); //DMA_SetPeriphIncMode Peripheral increment mode Disable 54 | MODIFY_REG(DMA1_Channel4_CCR, DMA_CCR_MINC, DMA_CCR_MINC); //DMA_SetMemoryIncMode 55 | MODIFY_REG(DMA1_Channel4_CCR, DMA_CCR_PSIZE, DMA_CCR_PSIZE_1); //ACD_SetMemorySize - 32 bit 56 | MODIFY_REG(DMA1_Channel4_CCR, DMA_CCR_MSIZE, DMA_CCR_MSIZE_0); //DMA_SetMemorySize - 16 bit 57 | 58 | 59 | SET_BIT(NVIC_ISER0, (1 << 14)); // Разрешить в NVIC прерывание #14 (DMA1_CH4) 60 | NVIC_IPR3 = 0x00000000; //Приоритет 0 61 | 62 | /* Configure the ACD functional parameters transmission */ 63 | WRITE_REG(DMA1_Channel4_CMAR, (uint32_t)Waveform_ADC); //Destination 64 | WRITE_REG(DMA1_Channel4_CPAR, (uint32_t)&(ADC1_DR)); //Source 65 | MODIFY_REG(DMA1_Channel4_CNDTR, DMA_CNDTR_NDT, WAVEFORM_SAMPLES_SIZE*2); //DMA_SetDataLength 66 | 67 | SET_BIT(DMA1_Channel4_CCR, DMA_CCR_TEIE | DMA_CCR_TCIE | DMA_CCR_HTIE ); //Enable DMA transfer interruption: transfer error, transfer complete, half transfer complete 68 | 69 | SET_BIT(DMA1_Channel4_CCR, DMA_CCR_EN); //Enable the DMA transfer 70 | 71 | SET_BIT(ADC1_CFGR, ADC_CFGR_DMAEN); //Enable ADC channel DMA request 72 | SET_BIT(ADC1_CFGR, ADC_CFGR_DMACFG); //DMA Circular mode selected 73 | 74 | SET_BIT(ADC1_CR, (1 << 0) | (1 << 2));// Включить ADC1 и начать преобразование 75 | SET_BIT(TIM2_CR1, TIM_CR1_CEN); //Запуск TIM2 - cтарт генерации сигнала дискретизации для ADC1 76 | 77 | } 78 | 79 | // Расчет параметра фильтра зависящего от частоты R=(2*Sin(PI*W))^2 80 | void KHZ_to_R(int fr) 81 | { 82 | R = (2*sin(M_PI*(0.998*fr)/FD)); 83 | R *= R; 84 | } 85 | 86 | 87 | // Обработчик прерывания от DMA. 88 | // Основной блок обработки массива отсчетов от ADC1. 89 | 90 | void DMA1_CH4_IRQHandler() 91 | { 92 | 93 | //Параметр, определяющий полосу пропускания фильтра dF 94 | //L ≈ 5.6 * Fd/FD 95 | static float L = 0.005; 96 | 97 | //Начальные значения переменных фильтра 98 | static float X = 0; 99 | static float V = 0; 100 | 101 | //Параметр интегрирующей цепочки 102 | static float K1 = WAVEFORM_SAMPLES_SIZE*(2*M_PI*FLPF/FD); //ФНЧ K = 2PI*f/fd 103 | static float K2 = WAVEFORM_SAMPLES_SIZE*(2*M_PI*FAGC/FD); //АРУ 104 | 105 | //Начальные значения переменных детектора 106 | static float U1 = 0; 107 | static float U2 = 0; 108 | static float AGCT = 1000; 109 | 110 | float M = 0.02; //Коэффициент компенсации передачи фильтра 111 | 112 | //Смещение для ADC и DAC 113 | static int S_ADC = 1975; // Uдел/3.3 * 4096 -> 1.586/3.29 *4096 = 1910 114 | static int S_DAC = 800; 115 | 116 | float D =0; 117 | int OUT,i; 118 | int16_t *Pointer; 119 | 120 | //Выбор буфера: первая половина Waveform_ADC/вторая половина Waveform_ADC 121 | if((DMA1_ISR & DMA_ISR_HTIF4)){ 122 | Pointer = Waveform_ADC; 123 | } else { 124 | Pointer = Waveform_ADC + WAVEFORM_SAMPLES_SIZE; 125 | } 126 | WRITE_REG(DMA1_IFCR, DMA_IFCR_CTCIF4 | DMA_IFCR_CHTIF4); 127 | 128 | //Обработка буфера 129 | for(i=0;i AGCT) 151 | OUT = U1*(AGCT/U2); 152 | 153 | OUT += S_DAC; 154 | 155 | // Ограничитель, предотвращает переполнение DAC при сильном сигнале 156 | if( OUT > 4000) OUT = 4000; 157 | 158 | //Запись в DAC 159 | DAC1_DHR12R1 = OUT; 160 | 161 | } 162 | -------------------------------------------------------------------------------- /12_SIMPLE_RADIO_DMA/Src/dac.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | //Выход DAC1 на PA4 5 | void DAC1_Init(void) 6 | { 7 | 8 | SET_BIT(RCC_AHB2ENR, RCC_AHB2ENR_DAC1EN ); // Подать тактовый сигнал на DAC1 9 | SET_BIT(DAC1_CR, 1); // Включить выход DAC1 10 | DAC1_DHR12R1 = 0; // Записать 0 в регистр данных DAC1 11 | 12 | } 13 | -------------------------------------------------------------------------------- /12_SIMPLE_RADIO_DMA/Src/encoder.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define FREQ_MAX 750 // Максимальное значение частоты KHz 7 | #define FREQ_MIN 150 // Минимальное значение частоты KHz 8 | #define FREQ_START 150 // Начальное значение частоты KHz 9 | 10 | void print(uint8_t x,uint8_t y,char *str); 11 | 12 | uint32_t frequency = FREQ_START; //Центральная частота полосы пропускания фильтра 13 | 14 | void KHZ_to_R(int fr); 15 | 16 | void FreqPrint() 17 | { 18 | static char ds[10] = " "; 19 | if( frequency > 9999 ) return; 20 | itoa(frequency, ds + 4 , 10); 21 | print(48,1,ds + strlen(ds + 4)); 22 | } 23 | 24 | void Encoder_Init(void) 25 | { 26 | 27 | /* Подключение выхода энкодера A (PA6) и B (PA7) к таймеру TIM3 */ 28 | 29 | // Включить PA6 и PA7 на альтерналивную функцию 30 | MODIFY_REG(GPIOA_MODER, GPIO_MODER_MODE7 | GPIO_MODER_MODE6, 2< FREQ_MAX) frequency = FREQ_MIN; 119 | TIM3_CNT = (frequency - FREQ_MIN) *2; 120 | KHZ_to_R(frequency); //Расчет значения R для фильтра 121 | FreqPrint(); 122 | } 123 | -------------------------------------------------------------------------------- /12_SIMPLE_RADIO_DMA/Src/gpio.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | void GpioInit(void) 5 | { 6 | SET_BIT(RCC_AHB2ENR, RCC_AHB2ENR_GPIOAEN | RCC_AHB2ENR_GPIOBEN); // Подать тактовый сигнал на GPIOA и GPIOB 7 | MODIFY_REG(GPIOB_MODER, GPIO_MODER_MODE8, 1< 2 | 3 | void GpioInit(void); 4 | void OLED_Init(void); 5 | void print(uint8_t x,uint8_t y,char *str); 6 | 7 | 8 | void TIM2_Init(void); 9 | void DAC1_Init(void); 10 | void ADC1_init(); 11 | void Encoder_Init(void); 12 | 13 | int main(void) 14 | { 15 | 16 | GpioInit(); //Настройка GPIO 17 | 18 | OLED_Init(); //Настройка OLED 19 | 20 | print(0,1,"Freq : KHz"); 21 | 22 | Encoder_Init(); //Настройка энкодера 23 | TIM2_Init(); //Настройка таймера TIM2 24 | DAC1_Init(); //Настройка ЦАП 25 | ADC1_init(); //Настройка и запуск АЦП 26 | 27 | while(1); 28 | 29 | } 30 | 31 | -------------------------------------------------------------------------------- /12_SIMPLE_RADIO_DMA/Src/stm32f4.ld: -------------------------------------------------------------------------------- 1 | /* Точка входа - функция sturt_up */ 2 | ENTRY(start_up) 3 | 4 | /* 5 | Начальные адреса и размер RAM и FLASH 6 | FLASH также аппаратно отображается в адреса 0x00000000 - 0x00020000 7 | */ 8 | 9 | MEMORY 10 | { 11 | RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 32K 12 | FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 128K 13 | } 14 | 15 | /* Размер таблицы векторов прерывания */ 16 | _size_vector_table = 0x0400; 17 | 18 | /* 19 | Вершина стека 20 | Находится в конце RAM 21 | */ 22 | _estack = ORIGIN(RAM) + LENGTH(RAM); 23 | 24 | 25 | SECTIONS { 26 | 27 | /* Секция векторов прерывания */ 28 | .vectors : { 29 | . = ALIGN(4); 30 | _svector = .; 31 | /*ключевое слово KEEP сохраняет раздел даже если на него нет ссылок*/ 32 | KEEP(*(.vectors)); 33 | . = _svector + _size_vector_table; 34 | . = ALIGN(4); 35 | _evector = .; 36 | } > FLASH 37 | 38 | /* Секция кода программы и констант*/ 39 | .text : { 40 | *(.text*) 41 | *(.rodata*) 42 | } > FLASH 43 | 44 | /* Секция глобальных переменных, инициализированных нулем */ 45 | .bss : { 46 | _sbss = .; 47 | *(.bss*) 48 | *(COMMON) 49 | . = ALIGN(4); 50 | _ebss = .; 51 | } > RAM 52 | 53 | /* Секция глобальных переменных, инициализированных константами */ 54 | .data : { 55 | _sdata_ram = .; 56 | *(.data*) 57 | . = ALIGN(4); 58 | _edata_ram = .; 59 | } > RAM AT > FLASH 60 | 61 | } 62 | 63 | /* Начальный и конечный адрес секции .data во flash памяти */ 64 | _sdata_flash = LOADADDR(.data); 65 | _edata_flash = _sdata_flash + SIZEOF(.data); 66 | 67 | 68 | -------------------------------------------------------------------------------- /12_SIMPLE_RADIO_DMA/Src/system_init.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* Константы определены в файле stm32f4.ld */ 4 | extern uint32_t _estack; 5 | extern uint32_t _sdata_ram, _edata_ram; 6 | extern uint32_t _sbss, _ebss; 7 | extern uint32_t _svector, _evector; 8 | extern uint32_t _sdata_flash, _edata_flash; 9 | 10 | void SystemClock_Config(void); 11 | int main(void); 12 | 13 | /* Точка входа */ 14 | void start_up(void) 15 | { 16 | uint32_t *src, *dst; 17 | 18 | /* Копирование данных секции .data из FLASH в RAM */ 19 | src = &_sdata_flash; 20 | dst = &_sdata_ram; 21 | while (dst < &_edata_ram) { 22 | *dst++ = *src++; 23 | } 24 | 25 | /* Запись нулей в область памяти секции .bss */ 26 | dst = &_sbss; 27 | while (dst < &_ebss) { 28 | *dst++ = 0; 29 | } 30 | 31 | /* FPU settings ------------------------------------------------------------*/ 32 | 33 | SCB_CPACR |= ((3UL << (10*2))|(3UL << (11*2))); /* set CP10 and CP11 Full Access */ 34 | 35 | SystemClock_Config(); 36 | main(); 37 | } 38 | 39 | 40 | 41 | void SystemClock_Config(void) 42 | { 43 | 44 | //Включить режим повышения выходного напряжения главного регулятора до 1,28 вольт 45 | CLEAR_BIT(PWR_CR5, PWR_CR5_R1MODE); 46 | 47 | //Установка задержки чтения FLASH памяти до 4-х тактов 48 | FLASH_ACR=FLASH_ACR_DBG_SWEN | FLASH_ACR_DCEN | FLASH_ACR_ICEN | FLASH_ACR_LATENCY_4WS ; 49 | while((FLASH_ACR & 0xf) != FLASH_ACR_LATENCY_4WS ); 50 | 51 | //Подключение внешнего кварцевого резонатора (HSE ON) 52 | SET_BIT(RCC_CR, RCC_CR_HSEON); 53 | while(READ_BIT(RCC_CR, RCC_CR_HSERDY) != (RCC_CR_HSERDY)); 54 | 55 | //Настройка PLL, используемого для SYSCLK домена 56 | //PLLM=6 (значение поля 5), PLLN=85 (значение поля 85), PLLR=2 (значение поля 0) 57 | MODIFY_REG(RCC_PLLCFGR, RCC_PLLCFGR_PLLSRC | RCC_PLLCFGR_PLLM | RCC_PLLCFGR_PLLN | RCC_PLLCFGR_PLLR, 58 | RCC_PLLCFGR_PLLSRC_HSE | 5 < 2 | 3 | void start_up(void); 4 | void nmi_handler(void); 5 | void hardfault_handler(void); 6 | void DMA1_CH4_IRQHandler(); 7 | void TIM3_IRQHandler(void); 8 | void EXTI9_5_IRQHandler(void); 9 | void DMA1_CH3_IRQHandler(); 10 | 11 | 12 | extern uint32_t _estack; 13 | 14 | /* Таблица векторов прерывания */ 15 | 16 | __attribute__ ((section(".vectors"),used))//Таблицу размещаем в секции .vectors 17 | uint32_t *vectors[] = { 18 | (uint32_t *) &_estack, //Вершина стека 19 | (uint32_t *) start_up, //Обработчик reset (точка входа) 20 | (uint32_t *) nmi_handler, //Обработчик немаскируемого прерывания 21 | (uint32_t *) hardfault_handler, //Обработчик прерывания аппаратной ошибки 22 | 0,0,0,0,0,0,0,0,0,0,0,0, //Окончание блока системных прерываний 23 | 0,0,0,0,0,0,0,0,0,0, //Прерывания 0 - 9 24 | 0,0,0, //Прерывания 10 -12 25 | (uint32_t *) DMA1_CH3_IRQHandler, //Прерывание 13, OLED 26 | (uint32_t *) DMA1_CH4_IRQHandler, //14 Обработчик прерывания от DMA1_CH4, ADC 27 | 0,0,0,0,0, //Прерывания 15 -19 28 | 0,0,0, //Прерывание 20 - 22 29 | (uint32_t *) EXTI9_5_IRQHandler, //23 Обработчик прерывания от EXTI9_5 (Encoder BUT) 30 | 0,0,0,0,0, //Прерывания 24 -28 31 | (uint32_t *) TIM3_IRQHandler //29 Обработчик прерывания от TIM3 (Encoder) 32 | }; 33 | 34 | /* Обработчик немаскируемого прерывания */ 35 | void nmi_handler(void) 36 | { 37 | for (;;); 38 | } 39 | 40 | /* Обработчик прерывания аппаратной ошибки */ 41 | void hardfault_handler(void) 42 | { 43 | for (;;); 44 | } 45 | -------------------------------------------------------------------------------- /13_SIMPLE_RADIO_DMA_ASM/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16_RADIO_II_ASM_DMA 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.cdt.managedbuilder.core.genmakebuilder 10 | clean,full,incremental, 11 | 12 | 13 | 14 | 15 | org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder 16 | full,incremental, 17 | 18 | 19 | 20 | 21 | 22 | com.st.stm32cube.ide.mcu.MCUProjectNature 23 | org.eclipse.cdt.core.cnature 24 | com.st.stm32cube.ide.mcu.MCUCubeIdeServicesRevAev2ProjectNature 25 | com.st.stm32cube.ide.mcu.MCUManagedMakefileProjectNature 26 | com.st.stm32cube.ide.mcu.MCUSingleCpuProjectNature 27 | com.st.stm32cube.ide.mcu.MCURootProjectNature 28 | org.eclipse.cdt.managedbuilder.core.managedBuildNature 29 | org.eclipse.cdt.managedbuilder.core.ScannerConfigNature 30 | 31 | 32 | -------------------------------------------------------------------------------- /13_SIMPLE_RADIO_DMA_ASM/Src/adc.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | #define PI 3.1415926 5 | 6 | #define WAVEFORM_SAMPLES_SIZE 64 //Длина буфера ADC (не забудь поменять в dsp.s) 7 | uint16_t Waveform_ADC[WAVEFORM_SAMPLES_SIZE*2]; //Два буфера 8 | 9 | void dsp_init(); 10 | 11 | /*************** Блок глобальных переменных обработки цифрового сигнала ***********************/ 12 | 13 | #define FD 3617 //Частота дискретизации KHz 14 | #define FLPF 2 //Частота перегиба ФНЧ KHz 15 | #define FAGC 0.001 //Частота перегиба АРУ KHz 16 | 17 | //Частота дискретизации 18 | float fd = FD; 19 | 20 | //Начальные значения переменных фильтра 1 21 | 22 | float L = 0.005; //L ≈ 5.6 * dF/FD 23 | float M = 0.01; //Коэффициент компенсации передачи фильтра 24 | 25 | //Параметр интегрирующей цепочки детектора 26 | float K1 = WAVEFORM_SAMPLES_SIZE*(2*PI*FLPF/FD); //K = 2PI*f/fd (Увеличивается в WAVEFORM_SAMPLES_SIZE раз) 27 | 28 | //Параметр интегрирующей цепочки АРУ 29 | float U2 = 0; 30 | float K2 = WAVEFORM_SAMPLES_SIZE*(2*PI*FAGC/FD); //K = 2PI*f/fd 31 | float AGCT = 1000; 32 | 33 | //Смещение для ADC и DAC необходимо точно подбирать! 34 | float S_ADC = 1910; // Uдел/3.3 * 4096 -> 1.54/3.3 *4096 = 1910 35 | //float S_ADC = 1681; // Uдел/3.3 * 4096 -> 1.35/3.29 *4096 = 1910 36 | float S_DAC = 800; 37 | 38 | //Массив коэффициентов линейной аппроксимации частоты фильтра 0 - 1600 KHz, шаг 100 KHz 39 | float A[17] = { 40 | 1.000,0.990,0.980,0.950,0.930, 41 | 0.890,0.840,0.800,0.740,0.680, 42 | 0.610,0.540,0.470,0.390,0.300, 43 | 0.230,0.100 44 | }; 45 | 46 | 47 | float B[17] = { 48 | 0.00,1.00,3.00,12.00,20.00, 49 | 40.00,70.00,98.00,146.00,200.00, 50 | 270.00,347.00,431.00,535.00,661.00, 51 | 766.00,974.00 52 | }; 53 | 54 | //Таймер, задающий частоту дискретизации ADC1 55 | void TIM2_Init(void) 56 | { 57 | 58 | SET_BIT(RCC_APB1ENR1, RCC_APB1ENR1_TIM2EN); // Подаем на TIM2 тактовую частоту 59 | TIM2_ARR = 170000/FD - 1; // Загружаем Auto-reload register f = 170 000 000/(TIM2_ARR+1), 1 MHz -> 170 -1 60 | TIM2_CR2 = TIM_CR2_MMS_1; // Выбор мастер режима таймера для возможности тактирования ADC 61 | 62 | } 63 | 64 | 65 | //Вход ADC1 на PA0 66 | void ADC1_init() 67 | { 68 | 69 | //Настройка тактирования ADC 70 | SET_BIT(RCC_CCIPR, 1 << 29 ); // Выбрать системный clock в качестве тактового сигнала для ADC 71 | SET_BIT(RCC_AHB2ENR, 1 << 13 ); // Подать тактовый сигнал на модуль ADC12 72 | SET_BIT(ADC12_COMMON_CCR, 2 << 16 ); // Выбрать в качестве тактового сигнала adc_hclk/2 73 | 74 | //Настройка режима ADC 75 | ADC1_CR = 0; // Сброс всех бит в ADC1_CR (ADEN = 0 для обеспечения конфигурирования) 76 | SET_BIT(ADC1_CR, 1 << 28); // Включить опорное напряжение ADC 77 | 78 | // Start calibration sequence 79 | ADC1_CR |= (1 << 31); 80 | while(ADC1_CR & (1 << 31)); // wait for calibration to finish 81 | 82 | // Запуск преобразования от TIM2_TRG0 (канал 11)(биты 5- 11), перезапись разрешена (бит 12) 83 | ADC1_CFGR = (1 << 12)+(1 << 10)+ (11 << 5); 84 | ADC1_SQR1 = (1 << 6); // Выбрать входной канал 1 (PA0) 85 | 86 | /* ADC1 DMA Init */ 87 | 88 | SET_BIT(RCC_AHB1ENR, RCC_AHB1ENR_DMAMUX1EN); //Подача тактового сигнала на DMAMUX1 89 | SET_BIT(RCC_AHB1ENR, RCC_AHB1ENR_DMA1EN); //Подача тактового сигнала на DMA1 90 | 91 | MODIFY_REG(DMAMUX1_Channel3_CCR, DMAMUX_CxCR_DMAREQ_ID, 5); //DMAMUX ADC1 request 92 | MODIFY_REG(DMA1_Channel4_CCR, DMA_CCR_DIR | DMA_CCR_MEM2MEM, 0); ////DMA_DIRECTION_PERIPH_TO_MEMORY 93 | MODIFY_REG(DMA1_Channel4_CCR, DMA_CCR_PL, DMA_CCR_PL_1); //DMA_SetChannelPriorityLevel 94 | MODIFY_REG(DMA1_Channel4_CCR, DMA_CCR_CIRC, DMA_CCR_CIRC); //DMA_SetMode CIRC 95 | MODIFY_REG(DMA1_Channel4_CCR, DMA_CCR_PINC, 0); //DMA_SetPeriphIncMode Peripheral increment mode Disable 96 | MODIFY_REG(DMA1_Channel4_CCR, DMA_CCR_MINC, DMA_CCR_MINC); //DMA_SetMemoryIncMode 97 | MODIFY_REG(DMA1_Channel4_CCR, DMA_CCR_PSIZE, DMA_CCR_PSIZE_1); //ACD_SetMemorySize - 32 bit 98 | MODIFY_REG(DMA1_Channel4_CCR, DMA_CCR_MSIZE, DMA_CCR_MSIZE_0); //DMA_SetMemorySize - 16 bit 99 | 100 | //Приоритеты DMA1_CH4 = 0 (ADC1, наивысший), DMA1_CH3 = 1 (print), 101 | //TIM3 = 2 (encoder) 102 | SET_BIT(NVIC_ISER0, (1 << 14)); // Разрешить в NVIC прерывание #14 (DMA1_CH4) Приоритет 0 103 | 104 | /* Configure the ACD functional parameters transmission */ 105 | WRITE_REG(DMA1_Channel4_CMAR, (uint32_t)Waveform_ADC); //Destination 106 | WRITE_REG(DMA1_Channel4_CPAR, (uint32_t)&(ADC1_DR)); //Source 107 | MODIFY_REG(DMA1_Channel4_CNDTR, DMA_CNDTR_NDT, WAVEFORM_SAMPLES_SIZE*2); //DMA_SetDataLength 108 | 109 | SET_BIT(DMA1_Channel4_CCR, DMA_CCR_TEIE | DMA_CCR_TCIE | DMA_CCR_HTIE ); //Enable DMA transfer interruption: transfer error, transfer complete, half transfer complete 110 | 111 | SET_BIT(DMA1_Channel4_CCR, DMA_CCR_EN); //Enable the DMA transfer 112 | 113 | SET_BIT(ADC1_CFGR, ADC_CFGR_DMAEN); //Enable ADC channel DMA request 114 | SET_BIT(ADC1_CFGR, ADC_CFGR_DMACFG); //DMA Circular mode selected 115 | 116 | SET_BIT(ADC1_CR, (1 << 0) | (1 << 2));// Включить ADC1 и начать преобразование 117 | SET_BIT(TIM2_CR1, TIM_CR1_CEN); //Запуск TIM2 - cтарт генерации сигнала дискретизации для ADC1 118 | 119 | dsp_init(); 120 | } 121 | 122 | 123 | -------------------------------------------------------------------------------- /13_SIMPLE_RADIO_DMA_ASM/Src/dac.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | //Выход DAC1 на PA4 5 | void DAC1_Init(void) 6 | { 7 | 8 | SET_BIT(RCC_AHB2ENR, RCC_AHB2ENR_DAC1EN ); // Подать тактовый сигнал на DAC1 9 | SET_BIT(DAC1_CR, 1); // Включить выход DAC1 10 | DAC1_DHR12R1 = 0; // Записать 0 в регистр данных DAC1 11 | 12 | } 13 | -------------------------------------------------------------------------------- /13_SIMPLE_RADIO_DMA_ASM/Src/dsp.s: -------------------------------------------------------------------------------- 1 | .syntax unified @ синтаксис исходного кода 2 | .thumb @ тип используемых инструкций Thumb 3 | .cpu cortex-m4 @ процессор 4 | .fpu fpv4-sp-d16 @ сопроцессор 5 | 6 | 7 | .globl dsp_init 8 | .globl KHZ_to_R 9 | .globl DMA1_CH4_IRQHandler 10 | 11 | //Общие константы 12 | .equ ADC1_ISR ,0x50000000 13 | .equ ADC1_DR ,0x50000040 14 | .equ DAC1_DHR12R1 ,0x50000808 15 | .equ GPIOB_ODR ,0x48000414 16 | .equ DMA1_ISR ,0x40020000 17 | .equ DMA1_IFCR ,0x40020004 18 | .equ DMA_ISR_HTIF4 ,0x00004000 19 | .equ DMA_IFCR_CTCIF4 ,0x00002000 20 | .equ DMA_IFCR_CHTIF4 ,0x00004000 21 | .equ WAVEFORM_SAMPLES_SIZE ,64 22 | 23 | .section .text. 24 | 25 | //Блок констант для быстрой загрузки в r1-r6 26 | const: 27 | .word Waveform_ADC 28 | .word WAVEFORM_SAMPLES_SIZE 29 | .word DMA1_ISR 30 | .word 0x6000 31 | .word DMA1_IFCR 32 | .word DAC1_DHR12R1 33 | PI2: 34 | .float 6.2831852 //2*PI 35 | 36 | //Размещение переменных в регистрах 37 | //s16 = X, s17 = V, s18 = R, s19 = L 38 | //s20 = M, s25 = U1, s26 = K1 39 | //s27 = U2, s28 = K2 40 | //s29 = S_ADC, s30 = S_DAC, s31 = AGCT 41 | 42 | //Инициализация регистров FPU 43 | .type dsp_init, %function 44 | dsp_init: 45 | push {r0,lr} 46 | 47 | vldr s0, =0 //s0 = 0 48 | vmov s16, s0 //X = 0 49 | vmov s17, s0 //V = 0 50 | vmov s25, s0 //U1 = 0 51 | vmov s27, s0 //U2 = 0 52 | 53 | ldr r0, =L 54 | vldr s19,[r0] //s19 = L 55 | ldr r0, =K1 56 | vldr s26,[r0] //s26 = K1 57 | ldr r0, =K2 58 | vldr s28,[r0] //s28 = K2 59 | ldr r0, =S_ADC 60 | vldr s29,[r0] //s29 = S_ADC 61 | ldr r0, =S_DAC 62 | vldr s30,[r0] //s30 = S_DAC 63 | ldr r0, =AGCT 64 | vldr s31,[r0] //s31 = AGCT 65 | ldr r0, =M 66 | vldr s20,[r0] //s20 = M 67 | 68 | pop {r0,pc} 69 | 70 | //Расчет параметров фильтра 71 | //Frc=A[Fr/100]+B[Fr/100] 72 | //R = (2*PI*Frc/Fd)^2 73 | .type KHZ_to_R, %function 74 | KHZ_to_R: 75 | push {r0,r1,lr} 76 | 77 | ldr r0, =frequency 78 | ldr r1, [r0] //r1 = Fr 79 | vldr s0, [r0] 80 | vcvt.f32.s32 s0, s0 //(float) s0 = (int), s0 = Fr 81 | 82 | mov r0, #100 83 | udiv r1,r0 84 | lsl r1,2 //r1 = index в массиве A[] и B[] 85 | 86 | ldr r0, =fd 87 | vldr s1, [r0] //s1 = Fd 88 | 89 | ldr r0, =A 90 | add r0,r1 91 | vldr s2, [r0] //s2 = A[F] 92 | 93 | ldr r0,=B 94 | add r0,r1 95 | vldr s3,[r0] //s3 = B[F] 96 | 97 | vfma.f32 s3,s0,s2 //s3 = s3 + s0*s2 -> Frc = B + A*Fr 98 | 99 | vdiv.f32 s4, s3,s1 // W = Frc/Fd для использования скоректированной частоты 100 | // vdiv.f32 s4, s0,s1 // W = Fr/Fd для калибровки шкалы 101 | 102 | // Расчет R = (2*PI*Frc/Fd)^2 103 | ldr r0, =PI2 104 | vldr s5, [r0] //2*PI 105 | vmul.f32 s5,s5,s4 //2*PI*W 106 | vmul.f32 s18,s5,s5 //s18 = (2*PI*W)^2 107 | 108 | pop {r0,r1,pc} 109 | 110 | 111 | 112 | // Основной блок обработки массива отсчетов от ADC1 113 | // r1 = pointer на буфер Waveform_ADC 114 | // r2 = количество элементов во входном массиве 115 | // r3 = адрес регистра DMA1_ISR 116 | // r4 = константа для анализа заполнения буфера 117 | // r5 = адрес регистра DMA1_IFCR 118 | // r6 = адрес регистра DAC1_DHR12R1 119 | // s16 = X, s17 = V, s18 = R, s19 = L 120 | // s20 = M, s25 = U1, s26 = K1 121 | // s27 = U2, s28 = K2 122 | // s29 = S_ADC, s30 = S_DAC, s31 = AGCT 123 | 124 | .type DMA1_CH4_IRQHandler, %function 125 | DMA1_CH4_IRQHandler: 126 | 127 | push {r0-r6,lr} 128 | 129 | // Раскомментировать для измерения скорости обработки 130 | /* mov r0, 0x80 //On PB7 131 | ldr r1, =GPIOB_ODR 132 | str r0, [r1] */ 133 | 134 | ldr r0, =const 135 | ldmia r0, {r1,r2,r3,r4,r5,r6} //Загрузка констант из массива const в регистры r1-r6 136 | 137 | // Анализ какая часть буфера Waveform_ADC заполнена 138 | ldr r0,[r3] //[DMA1_ISR] 139 | ands r0,DMA_ISR_HTIF4 140 | beq 1f 141 | add r1,WAVEFORM_SAMPLES_SIZE * 2 //Заполнена вторая часть буфера. 142 | //pointer += WAVEFORM_SAMPLES_SIZE * 2 143 | 1: 144 | str r4,[r5] // [DMA1_IFCR] Сброс прерывания 145 | 146 | 2: /************ Цикл обработки буфера Waveform_ADC *******************/ 147 | 148 | /************ Чтение одного отсчета *************/ 149 | ldrh r0, [r1] //r0 = [pointer] 150 | vmov s0, r0 //s0 = r0 151 | vcvt.f32.s32 s0, s0 //(float) s0 = (int) s0 152 | vsub.f32 s0, s29 //s0 = s0 - S_ADC 153 | 154 | /************ Фильтр 1 *******************/ 155 | 156 | vadd.f32 s16, s0 //X += s0 157 | 158 | //V -= X * R; 159 | vfms.f32 s17, s16, s18 //s17 = s17 - (s16 x s18) -> V -= X * R; 160 | 161 | //X += V - X * L; 162 | vadd.f32 s16,s17 //X = X + V 163 | vfms.f32 s16,s16,s19 //s16 = s16 - (s16 x s19) -> X -= X * L; 164 | 165 | //Детектор и интегрирующая цепочка 166 | vabs.f32 s0, s16 //s0 = abs(X) 167 | vadd.f32 s1, s0 //s1 sum of samples 168 | 169 | /************ Окончание цикла ************/ 170 | add r1, #2 //pointer += 2; 171 | subs r2, #1 //length -- 172 | bne 2b 173 | 174 | 175 | /************ Обработка НЧ части *****************/ 176 | 177 | vmul.f32 s1,s1,s20 //s1 = sum * M Компенсация коэффициента передачи фильтра 178 | 179 | /************ ФНЧ ********************************/ 180 | //U1+=(s1 - U1) * K1; 181 | vsub.f32 s0, s1, s25 //s0 = (abs-U1); 182 | vfma.f32 s25,s0,s26 //s25 = s25 + s0*s26 -> U1+=(ABS-U1)*K1; 183 | vmov s1, s25 //s1 = U1 184 | 185 | /************ АРУ *******************/ 186 | //U2 += (s0 - U2) * K2; 187 | vsub.f32 s0, s1, s27 //s0 = (abs-U2); 188 | vfma.f32 s27,s0,s28 //s27 = s27 + s0*s28 -> U2+=(ABS-U2)*K2; 189 | 190 | //if( U2 > AGCT) out = AGCT * s0/U2; 191 | vcmp.f32 s27,s31 //U2 < AGCT 192 | vmrs APSR_nzcv,FPSCR 193 | ble 3f 194 | vdiv.f32 s1, s1,s27 // s1 = U1/U2 195 | vmul.f32 s1, s1,s31 // s1 = s1 * AGCT 196 | 197 | 3: /************ ЦАП *******************/ 198 | 199 | vadd.f32 s1,s1,s30 // s1 = s1 + S_DAC 200 | vcvt.s32.f32 s1, s1 //(int) s1 = (float) s1 201 | vmov r0, s1 //r0 = (int) s1 202 | 203 | //if( r4 > 4095) r4 = 4095 204 | usat r0, #12, r0 //Saturation 205 | 206 | str r0, [r6] //DAC1_DHR12R1 207 | 208 | // Раскомментировать для измерения скорости обработки 209 | /* mov r0, 0x0 //On PB7 210 | ldr r1, =GPIOB_ODR 211 | str r0, [r1] */ 212 | 213 | pop {r0-r6,pc} 214 | -------------------------------------------------------------------------------- /13_SIMPLE_RADIO_DMA_ASM/Src/encoder.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define FREQ_MAX 1600 // Максимальное значение частоты KHz 7 | #define FREQ_MIN 150 // Минимальное значение частоты KHz 8 | #define FREQ_START 150 // Начальное значение частоты KHz 9 | 10 | void print(uint8_t x,uint8_t y,char *str); 11 | 12 | uint32_t frequency = FREQ_START; //Центральная частота полосы пропускания фильтра 13 | 14 | void KHZ_to_R(); 15 | 16 | void FreqPrint() 17 | { 18 | static char ds[10] = " "; 19 | if( frequency > 9999 ) return; 20 | itoa(frequency, ds + 4 , 10); 21 | print(48,1,ds + strlen(ds + 4)); 22 | } 23 | 24 | void Encoder_Init(void) 25 | { 26 | 27 | /* Подключение выхода энкодера A (PA6) и B (PA7) к таймеру TIM3 */ 28 | 29 | // Включить PA6 и PA7 на альтерналивную функцию 30 | MODIFY_REG(GPIOA_MODER, GPIO_MODER_MODE7 | GPIO_MODER_MODE6, 2< FREQ_MAX) frequency = FREQ_MIN; 120 | TIM3_CNT = (frequency - FREQ_MIN) *2; 121 | KHZ_to_R(); //Расчет значения R для фильтра 122 | FreqPrint(); 123 | } 124 | -------------------------------------------------------------------------------- /13_SIMPLE_RADIO_DMA_ASM/Src/gpio.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | void GpioInit(void) 5 | { 6 | SET_BIT(RCC_AHB2ENR, RCC_AHB2ENR_GPIOAEN | RCC_AHB2ENR_GPIOBEN); // Подать тактовый сигнал на GPIOA и GPIOB 7 | MODIFY_REG(GPIOB_MODER, GPIO_MODER_MODE8, 1< 2 | 3 | void GpioInit(void); 4 | void OLED_Init(void); 5 | void print(uint8_t x,uint8_t y,char *str); 6 | void TIM2_Init(void); 7 | void DAC1_Init(void); 8 | void ADC1_init(); 9 | void Encoder_Init(void); 10 | 11 | int main(void) 12 | { 13 | 14 | GpioInit(); 15 | OLED_Init(); 16 | 17 | print(0,1,"Freq: KHz"); 18 | 19 | Encoder_Init(); 20 | TIM2_Init(); 21 | DAC1_Init(); 22 | ADC1_init(); 23 | 24 | 25 | while(1){} 26 | 27 | } 28 | 29 | -------------------------------------------------------------------------------- /13_SIMPLE_RADIO_DMA_ASM/Src/stm32f4.ld: -------------------------------------------------------------------------------- 1 | /* Точка входа - функция sturt_up */ 2 | ENTRY(start_up) 3 | 4 | /* 5 | Начальные адреса и размер RAM и FLASH 6 | FLASH также аппаратно отображается в адреса 0x00000000 - 0x00020000 7 | */ 8 | 9 | MEMORY 10 | { 11 | RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 32K 12 | FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 128K 13 | } 14 | 15 | /* Размер таблицы векторов прерывания */ 16 | _size_vector_table = 0x0400; 17 | 18 | /* 19 | Вершина стека 20 | Находится в конце RAM 21 | */ 22 | _estack = ORIGIN(RAM) + LENGTH(RAM); 23 | 24 | 25 | SECTIONS { 26 | 27 | /* Секция векторов прерывания */ 28 | .vectors : { 29 | . = ALIGN(4); 30 | _svector = .; 31 | /*ключевое слово KEEP сохраняет раздел даже если на него нет ссылок*/ 32 | KEEP(*(.vectors)); 33 | . = _svector + _size_vector_table; 34 | . = ALIGN(4); 35 | _evector = .; 36 | } > FLASH 37 | 38 | /* Секция кода программы и констант*/ 39 | .text : { 40 | *(.text*) 41 | *(.rodata*) 42 | } > FLASH 43 | 44 | /* Секция глобальных переменных, инициализированных нулем */ 45 | .bss : { 46 | _sbss = .; 47 | *(.bss*) 48 | *(COMMON) 49 | . = ALIGN(4); 50 | _ebss = .; 51 | } > RAM 52 | 53 | /* Секция глобальных переменных, инициализированных константами */ 54 | .data : { 55 | _sdata_ram = .; 56 | *(.data*) 57 | . = ALIGN(4); 58 | _edata_ram = .; 59 | } > RAM AT > FLASH 60 | 61 | } 62 | 63 | /* Начальный и конечный адрес секции .data во flash памяти */ 64 | _sdata_flash = LOADADDR(.data); 65 | _edata_flash = _sdata_flash + SIZEOF(.data); 66 | 67 | 68 | -------------------------------------------------------------------------------- /13_SIMPLE_RADIO_DMA_ASM/Src/system_init.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* Константы определены в файле stm32f4.ld */ 4 | extern uint32_t _estack; 5 | extern uint32_t _sdata_ram, _edata_ram; 6 | extern uint32_t _sbss, _ebss; 7 | extern uint32_t _svector, _evector; 8 | extern uint32_t _sdata_flash, _edata_flash; 9 | 10 | void SystemClock_Config(void); 11 | int main(void); 12 | 13 | /* Точка входа */ 14 | void start_up(void) 15 | { 16 | uint32_t *src, *dst; 17 | 18 | /* Копирование данных секции .data из FLASH в RAM */ 19 | src = &_sdata_flash; 20 | dst = &_sdata_ram; 21 | while (dst < &_edata_ram) { 22 | *dst++ = *src++; 23 | } 24 | 25 | /* Запись нулей в область памяти секции .bss */ 26 | dst = &_sbss; 27 | while (dst < &_ebss) { 28 | *dst++ = 0; 29 | } 30 | 31 | /* FPU settings ------------------------------------------------------------*/ 32 | 33 | SCB_CPACR |= ((3UL << (10*2))|(3UL << (11*2))); /* set CP10 and CP11 Full Access */ 34 | 35 | SystemClock_Config(); 36 | main(); 37 | } 38 | 39 | 40 | 41 | void SystemClock_Config(void) 42 | { 43 | 44 | //Включить режим повышения выходного напряжения главного регулятора до 1,28 вольт 45 | CLEAR_BIT(PWR_CR5, PWR_CR5_R1MODE); 46 | 47 | //Установка задержки чтения FLASH памяти до 4-х тактов 48 | FLASH_ACR=FLASH_ACR_DBG_SWEN | FLASH_ACR_DCEN | FLASH_ACR_ICEN | FLASH_ACR_LATENCY_4WS ; 49 | while((FLASH_ACR & 0xf) != FLASH_ACR_LATENCY_4WS ); 50 | 51 | //Подключение внешнего кварцевого резонатора (HSE ON) 52 | SET_BIT(RCC_CR, RCC_CR_HSEON); 53 | while(READ_BIT(RCC_CR, RCC_CR_HSERDY) != (RCC_CR_HSERDY)); 54 | 55 | //Настройка PLL, используемого для SYSCLK домена 56 | //PLLM=6 (значение поля 5), PLLN=85 (значение поля 85), PLLR=2 (значение поля 0) 57 | MODIFY_REG(RCC_PLLCFGR, RCC_PLLCFGR_PLLSRC | RCC_PLLCFGR_PLLM | RCC_PLLCFGR_PLLN | RCC_PLLCFGR_PLLR, 58 | RCC_PLLCFGR_PLLSRC_HSE | 5 < 2 | 3 | void start_up(void); 4 | void nmi_handler(void); 5 | void hardfault_handler(void); 6 | void ADC1_IRQHandler(void); 7 | void TIM3_IRQHandler(void); 8 | void EXTI9_5_IRQHandler(void); 9 | void DMA1_CH3_IRQHandler(); 10 | void DMA1_CH4_IRQHandler(); 11 | 12 | extern uint32_t _estack; 13 | 14 | /* Таблица векторов прерывания */ 15 | 16 | __attribute__ ((section(".vectors"),used))//Таблицу размещаем в секции .vectors 17 | uint32_t *vectors[] = { 18 | (uint32_t *) &_estack, //Вершина стека 19 | (uint32_t *) start_up, //Обработчик reset (точка входа) 20 | (uint32_t *) nmi_handler, //Обработчик немаскируемого прерывания 21 | (uint32_t *) hardfault_handler, //Обработчик прерывания аппаратной ошибки 22 | 0,0,0,0,0,0,0,0,0,0,0,0, //Окончание блока системных прерываний 23 | 0,0,0,0,0,0,0,0,0,0, //Прерывания 0 - 9 24 | 0,0,0, //Прерывания 10 -12 25 | (uint32_t *) DMA1_CH3_IRQHandler, //Прерывание 13, OLED 26 | (uint32_t *) DMA1_CH4_IRQHandler, //14 Обработчик прерывания от DMA1_CH4, ADC 27 | 0,0,0, //Прерывания 15 -17 28 | 0, //Прерывание 18 29 | 0, //Прерывание 19 30 | 0,0,0, //Прерывание 20 - 22 31 | (uint32_t *) EXTI9_5_IRQHandler, //23 Обработчик прерывания от EXTI9_5 (Encoder BUT) 32 | 0,0,0,0,0, //Прерывания 24 -28 33 | (uint32_t *) TIM3_IRQHandler, //29 Обработчик прерывания от TIM3 (Encoder) 34 | 0,0,0,0,0,0,0,0,0,0, //Прерывания 30 -39 35 | }; 36 | 37 | /* Обработчик немаскируемого прерывания */ 38 | void nmi_handler(void) 39 | { 40 | for (;;); 41 | } 42 | 43 | /* Обработчик прерывания аппаратной ошибки */ 44 | void hardfault_handler(void) 45 | { 46 | for (;;); 47 | } 48 | -------------------------------------------------------------------------------- /13_SIMPLE_RADIO_DMA_ASM/Коррекция шкалы F I.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OlegDyakov/simple-radio/796e3d097773e1bceb4aa62bf3b16b425a8d1922/13_SIMPLE_RADIO_DMA_ASM/Коррекция шкалы F I.xlsx -------------------------------------------------------------------------------- /14_SIMPLE_RADIO_DMA_ASM_II/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | 14_SIMPLE_RADIO_DMA_ASM_II 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.cdt.managedbuilder.core.genmakebuilder 10 | clean,full,incremental, 11 | 12 | 13 | 14 | 15 | org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder 16 | full,incremental, 17 | 18 | 19 | 20 | 21 | 22 | com.st.stm32cube.ide.mcu.MCUProjectNature 23 | org.eclipse.cdt.core.cnature 24 | com.st.stm32cube.ide.mcu.MCUCubeIdeServicesRevAev2ProjectNature 25 | com.st.stm32cube.ide.mcu.MCUManagedMakefileProjectNature 26 | com.st.stm32cube.ide.mcu.MCUSingleCpuProjectNature 27 | com.st.stm32cube.ide.mcu.MCURootProjectNature 28 | org.eclipse.cdt.managedbuilder.core.managedBuildNature 29 | org.eclipse.cdt.managedbuilder.core.ScannerConfigNature 30 | 31 | 32 | -------------------------------------------------------------------------------- /14_SIMPLE_RADIO_DMA_ASM_II/Src/adc.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | #define PI 3.1415926 5 | 6 | #define WAVEFORM_SAMPLES_SIZE 64 //Длина буфера ADC (не забудь поменять в dsp.s) 7 | uint16_t Waveform_ADC[WAVEFORM_SAMPLES_SIZE*2]; //Два буфера 8 | 9 | void dsp_init(); 10 | 11 | /*************** Блок глобальных переменных обработки цифрового сигнала ***********************/ 12 | 13 | #define FD 3500 //Частота дискретизации KHz 14 | #define FLPF 2 //Частота перегиба ФНЧ KHz 15 | #define FAGC 0.001 //Частота перегиба АРУ KHz 16 | 17 | //Частота дискретизации 18 | float fd = FD; 19 | 20 | //Начальные значения переменных фильтров 21 | 22 | float L = 0.01; //L ≈ 5.6 * dF/FD 23 | float M = 0.0005; //Коэффициент компенсации передачи фильтра 24 | 25 | //Параметр интегрирующей цепочки детектора 26 | float K1 = WAVEFORM_SAMPLES_SIZE*(2*PI*FLPF/FD); //K = 2PI*f/fd (Увеличивается в WAVEFORM_SAMPLES_SIZE раз) 27 | 28 | //Параметр интегрирующей цепочки АРУ 29 | float U2 = 0; 30 | float K2 = WAVEFORM_SAMPLES_SIZE*(2*PI*FAGC/FD); //K = 2PI*f/fd 31 | float AGCT = 1000; //Порог АРУ 32 | 33 | //Смещение для ADC и DAC 34 | float S_ADC = 1910; // Uдел/3.3 * 4096 -> 1.54/3.3 *4096 = 1910 35 | float S_DAC = 800; 36 | 37 | //Массив коэффициентов линейной аппроксимации частоты фильтра 0 - 1600 KHz, шаг 100 KHz 38 | float A[17] = { 39 | 0.990,0.990,0.970,0.940,0.920, 40 | 0.880,0.830,0.780,0.720,0.660, 41 | 0.590,0.520,0.440,0.360,0.270, 42 | 0.190,0.150 43 | }; 44 | 45 | float B[17] = { 46 | 0.00,0.00,4.00,13.00,21.00, 47 | 41.00,71.00,106.00,154.00,208.00, 48 | 278.00,355.00,451.00,555.00,681.00, 49 | 801.00,865.00 50 | }; 51 | 52 | //Массив коэффициентов линейной аппроксимации коэф. передачи фильтра 0 - 1600 KHz, шаг 100 KHz 53 | float AA[17] = { 54 | 0.000,0.000,0.000,0.001,0.001, 55 | 0.001,0.002,0.002,0.003,0.005, 56 | 0.007,0.010,0.017,0.024,0.105, 57 | 0.282,0.504 58 | }; 59 | 60 | float BA[17] = { 61 | 1.00,0.95,0.98,0.91,0.68, 62 | 0.80,0.17,-0.17,-0.89,-2.20, 63 | -4.48,-8.15,-16.24,-24.70,-138.86, 64 | -404.23,-759.35 65 | }; 66 | 67 | //Таймер, задающий частоту дискретизации ADC1 68 | void TIM2_Init(void) 69 | { 70 | 71 | SET_BIT(RCC_APB1ENR1, RCC_APB1ENR1_TIM2EN); // Подаем на TIM2 тактовую частоту 72 | TIM2_ARR = 180000/FD - 1; // Загружаем Auto-reload register f = 170 000 000/(TIM2_ARR+1), 1 MHz -> 170 -1 73 | TIM2_CR2 = TIM_CR2_MMS_1; // Выбор мастер режима таймера для возможности тактирования ADC 74 | 75 | } 76 | 77 | 78 | //Вход ADC1 на PA0 79 | void ADC1_init() 80 | { 81 | 82 | //Настройка тактирования ADC 83 | SET_BIT(RCC_CCIPR, 1 << 28 ); // Выбрать системный выход PLL_P в качестве тактового сигнала для ADC 84 | SET_BIT(RCC_AHB2ENR, 1 << 13 ); // Подать тактовый сигнал на модуль ADC12 85 | SET_BIT(ADC12_COMMON_CCR, 2 << 16 ); // Выбрать в качестве тактового сигнала adc_hclk/2 (60 MHz) 86 | 87 | //Настройка режима ADC 88 | ADC1_CR = 0; // Сброс всех бит в ADC1_CR (ADEN = 0 для обеспечения конфигурирования) 89 | SET_BIT(ADC1_CR, 1 << 28); // Включить опорное напряжение ADC 90 | 91 | // Start calibration sequence 92 | ADC1_CR |= (1 << 31); 93 | while(ADC1_CR & (1 << 31)); // wait for calibration to finish 94 | 95 | // Запуск преобразования от TIM2_TRG0 (канал 11)(биты 5- 11), перезапись разрешена (бит 12) 96 | ADC1_CFGR = (1 << 12) + (1 << 10) + (11 << 5); //12 бит 97 | 98 | ADC1_SQR1 = (1 << 6); // Выбрать входной канал 1 (PA0) 99 | 100 | /* ADC1 DMA Init */ 101 | 102 | SET_BIT(RCC_AHB1ENR, RCC_AHB1ENR_DMAMUX1EN); //Подача тактового сигнала на DMAMUX1 103 | SET_BIT(RCC_AHB1ENR, RCC_AHB1ENR_DMA1EN); //Подача тактового сигнала на DMA1 104 | 105 | MODIFY_REG(DMAMUX1_Channel3_CCR, DMAMUX_CxCR_DMAREQ_ID, 5); //DMAMUX ADC1 request 106 | MODIFY_REG(DMA1_Channel4_CCR, DMA_CCR_DIR | DMA_CCR_MEM2MEM, 0); //DMA_DIRECTION_PERIPH_TO_MEMORY 107 | MODIFY_REG(DMA1_Channel4_CCR, DMA_CCR_PL, DMA_CCR_PL_1); //DMA_SetChannelPriorityLevel 108 | MODIFY_REG(DMA1_Channel4_CCR, DMA_CCR_CIRC, DMA_CCR_CIRC); //DMA_SetMode CIRC 109 | MODIFY_REG(DMA1_Channel4_CCR, DMA_CCR_PINC, 0); //DMA_SetPeriphIncMode Peripheral increment mode Disable 110 | MODIFY_REG(DMA1_Channel4_CCR, DMA_CCR_MINC, DMA_CCR_MINC); //DMA_SetMemoryIncMode 111 | MODIFY_REG(DMA1_Channel4_CCR, DMA_CCR_PSIZE, DMA_CCR_PSIZE_1); //ACD_SetMemorySize - 32 bit 112 | MODIFY_REG(DMA1_Channel4_CCR, DMA_CCR_MSIZE, DMA_CCR_MSIZE_0); //DMA_SetMemorySize - 16 bit 113 | 114 | //Приоритеты DMA1_CH4 = 0 (ADC1, наивысший), DMA1_CH3 = 1 (print), 115 | //TIM3 = 2 (encoder), TIM4 = 3 (level) 116 | SET_BIT(NVIC_ISER0, (1 << 14)); // Разрешить в NVIC прерывание #14 (DMA1_CH4) 117 | NVIC_IPR3 = 0x00000000; // Приоритет 0 для DMA1_CH4 118 | 119 | 120 | /* Configure the ACD functional parameters transmission */ 121 | WRITE_REG(DMA1_Channel4_CMAR, (uint32_t)Waveform_ADC); //Destination 122 | WRITE_REG(DMA1_Channel4_CPAR, (uint32_t)&(ADC1_DR)); //Source 123 | MODIFY_REG(DMA1_Channel4_CNDTR, DMA_CNDTR_NDT, WAVEFORM_SAMPLES_SIZE*2); //DMA_SetDataLength 124 | 125 | SET_BIT(DMA1_Channel4_CCR, DMA_CCR_TEIE | DMA_CCR_TCIE | DMA_CCR_HTIE ); //Enable DMA transfer interruption: transfer error, transfer complete, half transfer complete 126 | 127 | SET_BIT(DMA1_Channel4_CCR, DMA_CCR_EN); //Enable the DMA transfer 128 | 129 | SET_BIT(ADC1_CFGR, ADC_CFGR_DMAEN); //Enable ADC channel DMA request 130 | SET_BIT(ADC1_CFGR, ADC_CFGR_DMACFG); //DMA Circular mode selected 131 | 132 | SET_BIT(ADC1_CR, (1 << 0) | (1 << 2)); // Включить ADC1 и начать преобразование 133 | SET_BIT(TIM2_CR1, TIM_CR1_CEN); //Запуск TIM2 - cтарт генерации сигнала дискретизации для ADC1 134 | 135 | dsp_init(); //Инициализация регистров FPU 136 | } 137 | 138 | 139 | -------------------------------------------------------------------------------- /14_SIMPLE_RADIO_DMA_ASM_II/Src/dac.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | //Выход DAC1 на PA4 5 | void DAC1_Init(void) 6 | { 7 | 8 | SET_BIT(RCC_AHB2ENR, RCC_AHB2ENR_DAC1EN ); // Подать тактовый сигнал на DAC1 9 | SET_BIT(DAC1_CR, 1); // Включить выход DAC1 10 | DAC1_DHR12R1 = 0; // Записать 0 в регистр данных DAC1 11 | 12 | } 13 | -------------------------------------------------------------------------------- /14_SIMPLE_RADIO_DMA_ASM_II/Src/dsp.s: -------------------------------------------------------------------------------- 1 | .syntax unified @ синтаксис исходного кода 2 | .thumb @ тип используемых инструкций Thumb 3 | .cpu cortex-m4 @ процессор 4 | .fpu fpv4-sp-d16 @ сопроцессор 5 | 6 | .globl dsp_init 7 | .globl KHZ_to_R 8 | .globl DMA1_CH4_IRQHandler 9 | .global CopyRA_toReg 10 | .global GetAGCLevel 11 | 12 | //Общие константы 13 | .equ ADC1_ISR ,0x50000000 14 | .equ ADC1_DR ,0x50000040 15 | .equ DAC1_DHR12R1 ,0x50000808 16 | .equ GPIOB_ODR ,0x48000414 17 | .equ DMA1_ISR ,0x40020000 18 | .equ DMA1_IFCR ,0x40020004 19 | .equ DMA_ISR_HTIF4 ,0x00004000 20 | .equ DMA_IFCR_CTCIF4 ,0x00002000 21 | .equ DMA_IFCR_CHTIF4 ,0x00004000 22 | .equ WAVEFORM_SAMPLES_SIZE ,64 23 | 24 | .section .text. 25 | 26 | //Блок констант для быстрой загрузки в r1-r6 27 | const: 28 | .word Waveform_ADC 29 | .word WAVEFORM_SAMPLES_SIZE 30 | .word DMA1_ISR 31 | .word 0x6000 32 | .word DMA1_IFCR 33 | .word DAC1_DHR12R1 34 | PI2: 35 | .float 6.2831852 //2*PI 36 | 37 | //Размещение переменных в регистрах 38 | //s16 = X1, s17 = V1, s18 = R, s19 = L 39 | //s20 = X2, s21 = V2, s24 = M 40 | //s25 = U1, s26 = K1 41 | //s27 = U2, s28 = K2 42 | //s29 = S_ADC, s30 = S_DAC, s31 = AGCT 43 | 44 | 45 | //Инициализация регистров FPU 46 | .type dsp_init, %function 47 | dsp_init: 48 | push {r0,lr} 49 | vldr s0, =0 //s0 = 0 50 | vmov s16, s0 //X1 = 0 51 | vmov s17, s0 //V1 = 0 52 | vmov s20, s0 //X2 = 0 53 | vmov s21, s0 //V2 = 0 54 | vmov s25, s0 //U1 = 0 55 | vmov s27, s0 //U2 = 0 56 | 57 | ldr r0, =L 58 | vldr s19,[r0] //s19 = L 59 | ldr r0, =K1 60 | vldr s26,[r0] //s26 = K1 61 | ldr r0, =K2 62 | vldr s28,[r0] //s28 = K2 63 | ldr r0, =S_ADC 64 | vldr s29,[r0] //s29 = S_ADC 65 | ldr r0, =S_DAC 66 | vldr s30,[r0] //s30 = S_DAC 67 | ldr r0, =AGCT 68 | vldr s31,[r0] //s31 = AGCT 69 | ldr r0, =M 70 | vldr s24,[r0] //s24 = M 71 | 72 | pop {r0,pc} 73 | 74 | 75 | //Расчет параметров фильтра 76 | //Frc=A[Fr/100]+B[Fr/100] 77 | //R = (2*PI*Frc/Fd)^2 78 | 79 | .type KHZ_to_R, %function 80 | KHZ_to_R: 81 | push {r0,r1,lr} 82 | 83 | ldr r0, =frequency 84 | ldr r1, [r0] //r1 = Fr 85 | vldr s0, [r0] 86 | vcvt.f32.s32 s0, s0 //(float) s0 = (int), s0 = Fr 87 | 88 | mov r0, #100 89 | udiv r1,r0 90 | lsl r1,2 //r1 = index в массиве A[] и B[] 91 | 92 | ldr r0, =fd 93 | vldr s1, [r0] //s1 = Fd 94 | 95 | ldr r0, =A 96 | add r0, r1 97 | vldr s2, [r0] //s2 = A[F] 98 | 99 | ldr r0,=B 100 | add r0,r1 101 | vldr s3,[r0] //s3 = B[F] 102 | 103 | vfma.f32 s3,s0,s2 //s3 = s3 + s0*s2 -> Frc = B + A*Fr 104 | 105 | vdiv.f32 s4, s3,s1 // W = Frc/Fd для использования скоректированной частоты 106 | // vdiv.f32 s4, s0,s1 // W = Fr/Fd для калибровки шкалы 107 | 108 | // Расчет R = (2*PI*Frc/Fd)^2 109 | ldr r0, =PI2 110 | vldr s5, [r0] //2*PI 111 | vmul.f32 s5,s5,s4 //2*PI*W 112 | vmul.f32 s18,s5,s5 //s18 = (2*PI*W)^2 113 | 114 | //Коррекция M 115 | 116 | ldr r0, =AA 117 | add r0, r1 118 | vldr s1, [r0] //AA[i] 119 | 120 | ldr r0, =BA 121 | add r0, r1 122 | vldr s2, [r0] //BA[i] 123 | vfma.f32 s2,s1,s0 //s2 = s2 + s1*s0 -> Mc = BA + AA[i]*M 124 | 125 | ldr r0, = M 126 | vldr s24,[r0] //s24 = M 127 | 128 | vdiv.f32 s24, s24,s2 // M = M/K 129 | 130 | pop {r0,r1,pc} 131 | 132 | 133 | //Получение уровня сигнала 134 | //Запись значения S27 в переменную U2 135 | .type GetAGCLevel, %function 136 | GetAGCLevel: 137 | 138 | push {r0,lr} 139 | ldr r0, =U2 140 | vstr s27,[r0] //U2 = s27 141 | pop {r0,pc} 142 | 143 | 144 | // Основной блок обработки массива отсчетов от ADC1 145 | // r1 = pointer на буфер Waveform_ADC 146 | // r2 = количество элементов во входном массиве 147 | // r3 = адрес регистра DMA1_ISR 148 | // r4 = константа для анализа заполнения буфера 149 | // r5 = адрес регистра DMA1_IFCR 150 | // r6 = адрес регистра DAC1_DHR12R1 151 | // s16 = X1, s17 = V1, s18 = R, s19 = L 152 | // s20 = X2, s21 = V2, s24 = M 153 | // s25 = U1, s26 = K1 154 | // s27 = U2, s28 = K2 155 | // s29 = S_ADC, s30 = S_DAC, s31 = AGCT 156 | 157 | .type DMA1_CH4_IRQHandler, %function 158 | DMA1_CH4_IRQHandler: 159 | 160 | push {r0-r6,lr} 161 | 162 | // Раскомментировать для измерения скорости обработки 163 | /* mov r0, 0x80 //On PB7 164 | ldr r1, =GPIOB_ODR 165 | str r0, [r1] */ 166 | 167 | ldr r0, =const 168 | ldmia r0, {r1,r2,r3,r4,r5,r6} //Загрузка констант из массива const в регистры r1-r6 169 | 170 | // Анализ какая часть буфера Waveform_ADC заполнена 171 | ldr r0,[r3] //[DMA1_ISR] 172 | ands r0,DMA_ISR_HTIF4 173 | beq 1f 174 | add r1,WAVEFORM_SAMPLES_SIZE * 2 //Заполнена вторая часть буфера. 175 | //pointer += WAVEFORM_SAMPLES_SIZE * 2 176 | 1: 177 | str r4,[r5] // [DMA1_IFCR] Сброс прерывания 178 | 179 | 2: /************ Цикл обработки буфера Waveform_ADC *******************/ 180 | 181 | /************ Чтение одного отсчета *************/ 182 | ldrh r0, [r1] //r0 = [pointer] 183 | vmov s0, r0 //s0 = r0 184 | vcvt.f32.s32 s0, s0 //(float) s0 = (int) s0 185 | vsub.f32 s0, s29 //s0 = s0 - S_ADC 186 | 187 | /************ Фильтр 1 *******************/ 188 | 189 | vadd.f32 s16, s0 //X1 += s0 190 | 191 | //V -= X * R; 192 | vfms.f32 s17, s16, s18 //s17 = s17 - (s16 x s18) -> V1 -= X1 * R; 193 | 194 | //X1 += V1 - X1 * L; 195 | vadd.f32 s16,s17 //X1 = X1 + V1 196 | vfms.f32 s16,s16,s19 //s16 = s16 - (s16 x s19) -> X1 -= X1 * L; 197 | 198 | /************ Фильтр 2 *******************/ 199 | 200 | vadd.f32 s20, s16 //X2 += X1 201 | 202 | //V2 -= X2 * R; 203 | vfms.f32 s21, s20, s18 //s21 = s21 - (s20 x s18) -> V2 -= X2 * R; 204 | 205 | //X2 += V2 - X2 * L; 206 | vadd.f32 s20,s21 //X2 = X2 + V2 207 | vfms.f32 s20,s20,s19 //s20 = s20 - (s20 x s19) -> X2 -= X2 * L; 208 | 209 | //X2 += V2 - X2 * L; 210 | // vmul.f32 s0,s20,s19 //s0 = X2*L 211 | // vsub.f32 s0,s21,s0 //s0 = V2 - s0 212 | // vadd.f32 s20,s0 //X2 = X2 + s0 213 | 214 | 215 | //Детектор и интегрирующая цепочка 216 | vabs.f32 s0, s20 //s0 = abs(X2) 217 | vadd.f32 s1, s0 //s1 sum of samples 218 | 219 | /************ Окончание цикла ************/ 220 | add r1, #2 //pointer += 2; 221 | subs r2, #1 //length -- 222 | bne 2b 223 | 224 | 225 | /************ Обработка НЧ части *****************/ 226 | 227 | vmul.f32 s1,s1,s24 //s1 = sum * M Компенсация коэффициента передачи фильтра 228 | 229 | /************ ФНЧ ********************************/ 230 | //U1+=(s1 - U1) * K1; 231 | vsub.f32 s0, s1, s25 //s0 = (abs-U1); 232 | vfma.f32 s25,s0,s26 //s25 = s25 + s0*s26 -> U1+=(ABS-U1)*K1; 233 | vmov s1, s25 //s1 = U1 234 | 235 | /************ АРУ *******************/ 236 | //U2 += (s0 - U2) * K2; 237 | vsub.f32 s0, s1, s27 //s0 = (abs-U2); 238 | vfma.f32 s27,s0,s28 //s27 = s27 + s0*s28 -> U2+=(ABS-U2)*K2; 239 | 240 | //if( U2 > AGCT) out = AGCT * s0/U2; 241 | vcmp.f32 s27,s31 //U2 < AGCT 242 | vmrs APSR_nzcv,FPSCR 243 | ble 3f 244 | vdiv.f32 s1, s1,s27 // s1 = U1/U2 245 | vmul.f32 s1, s1,s31 // s1 = s1 * AGCT 246 | 247 | 3: /************ ЦАП *******************/ 248 | 249 | vadd.f32 s1,s1,s30 // s1 = s1 + S_DAC 250 | vcvt.s32.f32 s1, s1 //(int) s1 = (float) s1 251 | vmov r0, s1 //r0 = (int) s1 252 | 253 | //if( r4 > 4095) r4 = 4095 254 | usat r0, #12, r0 //Saturation 255 | 256 | str r0, [r6] //DAC1_DHR12R1 257 | 258 | // Раскомментировать для измерения скорости обработки 259 | /* mov r0, 0x0 //On PB7 260 | ldr r1, =GPIOB_ODR 261 | str r0, [r1] */ 262 | 263 | pop {r0-r6,pc} 264 | 265 | -------------------------------------------------------------------------------- /14_SIMPLE_RADIO_DMA_ASM_II/Src/encoder.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define FREQ_MAX 1650 // Максимальное значение частоты KHz 7 | #define FREQ_MIN 150// Минимальное значение частоты KHz 8 | #define FREQ_START 150// Начальное значение частоты KHz 9 | 10 | void print(uint8_t x,uint8_t y,char *str); 11 | 12 | uint32_t frequency = FREQ_START; //Центральная частота полосы пропускания фильтра 13 | 14 | void KHZ_to_R(); 15 | 16 | void FreqPrint() 17 | { 18 | static char ds[10] = " "; 19 | if( frequency > 9999 ) return; 20 | itoa(frequency, ds + 4 , 10); 21 | print(48,0,ds + strlen(ds + 4)); 22 | } 23 | 24 | void Encoder_Init(void) 25 | { 26 | 27 | /* Подключение выхода энкодера A (PA6) и B (PA7) к таймеру TIM3 */ 28 | 29 | // Включить PA6 и PA7 на альтерналивную функцию 30 | MODIFY_REG(GPIOA_MODER, GPIO_MODER_MODE7 | GPIO_MODER_MODE6, 2< FREQ_MAX) frequency = FREQ_MIN; 120 | TIM3_CNT = (frequency - FREQ_MIN) *2; 121 | KHZ_to_R(); //Расчет значения R для фильтра 122 | FreqPrint(); 123 | } 124 | -------------------------------------------------------------------------------- /14_SIMPLE_RADIO_DMA_ASM_II/Src/gpio.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | void GpioInit(void) 5 | { 6 | SET_BIT(RCC_AHB2ENR, RCC_AHB2ENR_GPIOAEN | RCC_AHB2ENR_GPIOBEN); // Подать тактовый сигнал на GPIOA и GPIOB 7 | MODIFY_REG(GPIOB_MODER, GPIO_MODER_MODE8, 1< 2 | #include 3 | #include 4 | 5 | void print(uint8_t x,uint8_t y,char *str); 6 | int IsDMA_Busy(void); 7 | void GetAGCLevel(void); 8 | 9 | extern float U2; //Уровень АРУ 10 | 11 | void TIM4_Init(void) 12 | { 13 | 14 | SET_BIT(RCC_APB1ENR1, RCC_APB1ENR1_TIM4EN); // Подаем на TIM4 тактовую частоту 15 | TIM4_PSC = 10000 - 1; // Загружаем TIMx prescaler Fclk = 180 000 000 / (PSC[15:0] + 1) 16 | TIM4_ARR = 18000 - 1; // Загружаем Auto-reload register f = Fclk/(ARR[15:0]+1) (1Hz -> 17000 - 1) 17 | 18 | SET_BIT(NVIC_ISER0, (1 << 30)); // Разрешить в NVIC прерывание #30 (TIM4) 19 | NVIC_IPR7 = 0x00300000; // Установка приоритета 3 для прерывания 30. 20 | 21 | SET_BIT(TIM4_DIER, TIM_DIER_UIE); // Разрешить прерывание по переполнению таймера 22 | SET_BIT(TIM4_CR1, TIM_CR1_CEN); // Включить таймер 23 | } 24 | 25 | 26 | void TIM4_IRQHandler(void) 27 | { 28 | CLEAR_BIT(TIM4_SR, TIM_SR_UIF); //Сброс флага переполнения 29 | if(IsDMA_Busy()) return; 30 | GetAGCLevel(); 31 | int d = U2; 32 | d = d/10; 33 | static char ds[10] = " "; 34 | if( d > 9999 ) return; 35 | itoa(d, ds + 4 , 10); 36 | print(48,2,ds + strlen(ds + 4)); 37 | } 38 | -------------------------------------------------------------------------------- /14_SIMPLE_RADIO_DMA_ASM_II/Src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void GpioInit(void); 4 | void OLED_Init(void); 5 | void print(uint8_t x,uint8_t y,char *str); 6 | 7 | void TIM2_Init(void); 8 | void DAC1_Init(void); 9 | void ADC1_init(); 10 | void Encoder_Init(void); 11 | void TIM4_Init(void); 12 | 13 | int main(void) 14 | { 15 | 16 | GpioInit(); 17 | TIM4_Init(); 18 | OLED_Init(); 19 | 20 | print(0,0,"Freq : KHz"); 21 | print(0,2,"Level: 1"); 22 | 23 | Encoder_Init(); 24 | 25 | TIM2_Init(); 26 | DAC1_Init(); 27 | ADC1_init(); 28 | 29 | 30 | while(1){} 31 | 32 | } 33 | 34 | -------------------------------------------------------------------------------- /14_SIMPLE_RADIO_DMA_ASM_II/Src/stm32f4.ld: -------------------------------------------------------------------------------- 1 | /* Точка входа - функция sturt_up */ 2 | ENTRY(start_up) 3 | 4 | /* 5 | Начальные адреса и размер RAM и FLASH 6 | FLASH также аппаратно отображается в адреса 0x00000000 - 0x00020000 7 | */ 8 | 9 | MEMORY 10 | { 11 | RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 32K 12 | FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 128K 13 | } 14 | 15 | /* Размер таблицы векторов прерывания */ 16 | _size_vector_table = 0x0400; 17 | 18 | /* 19 | Вершина стека 20 | Находится в конце RAM 21 | */ 22 | _estack = ORIGIN(RAM) + LENGTH(RAM); 23 | 24 | 25 | SECTIONS { 26 | 27 | /* Секция векторов прерывания */ 28 | .vectors : { 29 | . = ALIGN(4); 30 | _svector = .; 31 | /*ключевое слово KEEP сохраняет раздел даже если на него нет ссылок*/ 32 | KEEP(*(.vectors)); 33 | . = _svector + _size_vector_table; 34 | . = ALIGN(4); 35 | _evector = .; 36 | } > FLASH 37 | 38 | /* Секция кода программы и констант*/ 39 | .text : { 40 | *(.text*) 41 | *(.rodata*) 42 | } > FLASH 43 | 44 | /* Секция глобальных переменных, инициализированных нулем */ 45 | .bss : { 46 | _sbss = .; 47 | *(.bss*) 48 | *(COMMON) 49 | . = ALIGN(4); 50 | _ebss = .; 51 | } > RAM 52 | 53 | /* Секция глобальных переменных, инициализированных константами */ 54 | .data : { 55 | _sdata_ram = .; 56 | *(.data*) 57 | . = ALIGN(4); 58 | _edata_ram = .; 59 | } > RAM AT > FLASH 60 | 61 | } 62 | 63 | /* Начальный и конечный адрес секции .data во flash памяти */ 64 | _sdata_flash = LOADADDR(.data); 65 | _edata_flash = _sdata_flash + SIZEOF(.data); 66 | 67 | 68 | -------------------------------------------------------------------------------- /14_SIMPLE_RADIO_DMA_ASM_II/Src/system_init.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* Константы определены в файле stm32f4.ld */ 4 | extern uint32_t _estack; 5 | extern uint32_t _sdata_ram, _edata_ram; 6 | extern uint32_t _sbss, _ebss; 7 | extern uint32_t _svector, _evector; 8 | extern uint32_t _sdata_flash, _edata_flash; 9 | 10 | void SystemClock_Config(void); 11 | int main(void); 12 | 13 | /* Точка входа */ 14 | void start_up(void) 15 | { 16 | uint32_t *src, *dst; 17 | 18 | /* Копирование данных секции .data из FLASH в RAM */ 19 | src = &_sdata_flash; 20 | dst = &_sdata_ram; 21 | while (dst < &_edata_ram) { 22 | *dst++ = *src++; 23 | } 24 | 25 | /* Запись нулей в область памяти секции .bss */ 26 | dst = &_sbss; 27 | while (dst < &_ebss) { 28 | *dst++ = 0; 29 | } 30 | 31 | /* FPU settings ------------------------------------------------------------*/ 32 | 33 | SCB_CPACR |= ((3UL << (10*2))|(3UL << (11*2))); /* set CP10 and CP11 Full Access */ 34 | 35 | SystemClock_Config(); 36 | main(); 37 | } 38 | 39 | 40 | 41 | void SystemClock_Config(void) 42 | { 43 | 44 | //Включить режим повышения выходного напряжения главного регулятора до 1,28 вольт 45 | CLEAR_BIT(PWR_CR5, PWR_CR5_R1MODE); 46 | 47 | //Установка задержки чтения FLASH памяти до 4-х тактов 48 | FLASH_ACR=FLASH_ACR_DBG_SWEN | FLASH_ACR_DCEN | FLASH_ACR_ICEN | FLASH_ACR_LATENCY_4WS ; 49 | while((FLASH_ACR & 0xf) != FLASH_ACR_LATENCY_4WS ); 50 | 51 | //Подключение внешнего кварцевого резонатора (HSE ON) 52 | SET_BIT(RCC_CR, RCC_CR_HSEON); 53 | while(READ_BIT(RCC_CR, RCC_CR_HSERDY) != (RCC_CR_HSERDY)); 54 | 55 | //f(VCO clock) = f(PLL clock input) × (PLLN / PLLM) = 24 x 90 / 6 = 360 MHz 56 | //Настройка PLL, используемого для SYSCLK домена SYSCLK = 180 MHz, adc_hclk = 120MHz 57 | //PLLM=6 (значение поля 5), PLLN=90 (значение поля 90), PLLR=2 (значение поля 0) 58 | MODIFY_REG(RCC_PLLCFGR, RCC_PLLCFGR_PLLPDIV | RCC_PLLCFGR_PLLSRC | RCC_PLLCFGR_PLLM | RCC_PLLCFGR_PLLN | RCC_PLLCFGR_PLLR, 59 | 3<< RCC_PLLCFGR_PLLPDIV_Pos | RCC_PLLCFGR_PLLSRC_HSE | 5 < 2 | 3 | void start_up(void); 4 | void nmi_handler(void); 5 | void hardfault_handler(void); 6 | void ADC1_IRQHandler(void); 7 | void TIM3_IRQHandler(void); 8 | void TIM4_IRQHandler(void); 9 | void EXTI9_5_IRQHandler(void); 10 | void DMA1_CH3_IRQHandler(); 11 | void DMA1_CH4_IRQHandler(); 12 | 13 | extern uint32_t _estack; 14 | 15 | /* Таблица векторов прерывания */ 16 | 17 | __attribute__ ((section(".vectors"),used))//Таблицу размещаем в секции .vectors 18 | uint32_t *vectors[] = { 19 | (uint32_t *) &_estack, //Вершина стека 20 | (uint32_t *) start_up, //Обработчик reset (точка входа) 21 | (uint32_t *) nmi_handler, //Обработчик немаскируемого прерывания 22 | (uint32_t *) hardfault_handler, //Обработчик прерывания аппаратной ошибки 23 | 0,0,0,0,0,0,0,0,0,0,0,0, //Окончание блока системных прерываний 24 | 0,0,0,0,0,0,0,0,0,0, //Прерывания 0 - 9 25 | 0,0,0, //Прерывания 10 -12 26 | (uint32_t *) DMA1_CH3_IRQHandler, //Прерывание 13, OLED 27 | (uint32_t *) DMA1_CH4_IRQHandler, //14 Обработчик прерывания от DMA1_CH4, ADC 28 | 0,0,0, //Прерывания 15 -17 29 | 0, //Прерывание 18 30 | 0, //Прерывание 19 31 | 0,0,0, //Прерывание 20 - 22 32 | (uint32_t *) EXTI9_5_IRQHandler, //23 Обработчик прерывания от EXTI9_5 (Encoder BUT) 33 | 0,0,0,0,0, //Прерывания 24 -28 34 | (uint32_t *) TIM3_IRQHandler, //29 Обработчик прерывания от TIM3 (Encoder) 35 | (uint32_t *) TIM4_IRQHandler, //30 Обработчик прерывания от TIM4 (Level) 36 | 0,0,0,0,0,0,0,0,0, //Прерывания 31 -39 37 | }; 38 | 39 | /* Обработчик немаскируемого прерывания */ 40 | void nmi_handler(void) 41 | { 42 | for (;;); 43 | } 44 | 45 | /* Обработчик прерывания аппаратной ошибки */ 46 | void hardfault_handler(void) 47 | { 48 | for (;;); 49 | } 50 | -------------------------------------------------------------------------------- /14_SIMPLE_RADIO_DMA_ASM_II/Коррекция шкалы F II.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OlegDyakov/simple-radio/796e3d097773e1bceb4aa62bf3b16b425a8d1922/14_SIMPLE_RADIO_DMA_ASM_II/Коррекция шкалы F II.xlsx -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # simple-radio 2 | Обучающие проекты по созданию простого цифрового радиоприемника на базе микроконтроллера STM32G431KB. 3 | 4 | Разработка программ выполнялась в Windows 10 с использованием бесплатной интегрированной среды разработки STM32CubeIDE от компании STMicrielectronics (https://www.st.com/en/development-tools/stm32cubeide.html). 5 | 6 | A set of tutorial projects for creating a simple digital radio receiver based on the STM32G431KB microcontroller. 7 | -------------------------------------------------------------------------------- /Простой цифровой радиоприемник V3.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OlegDyakov/simple-radio/796e3d097773e1bceb4aa62bf3b16b425a8d1922/Простой цифровой радиоприемник V3.pdf --------------------------------------------------------------------------------