├── 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
--------------------------------------------------------------------------------