编程技术分享

分享编程知识,探讨技术创新

0%

简介:立创逻辑派FPGA-G1开发板,搭载国产高云GW2A-LV18,融合GD32F303的M4内核。提供入门资料和近百款模块移植案例、步骤清晰的教程帮助初学者更快地掌握FPGA基础知识。

好的,作为一名高级嵌入式软件开发工程师,我将针对立创逻辑派FPGA-G1开发板,结合其国产高云GW2A-LV18 FPGA和GD32F303 M4内核的特性,详细阐述一个可靠、高效、可扩展的嵌入式系统开发流程,并给出相应的代码架构和C语言实现。
关注微信公众号,提前获取相关推文

系统概述

立创逻辑派FPGA-G1开发板是一个强大的混合架构平台,它结合了FPGA的并行处理能力和微控制器的灵活性。这种架构非常适合于需要高性能计算和实时控制的应用场景。我们的系统设计目标是充分利用这两种资源的优势,构建一个模块化、可重用、易于维护和升级的嵌入式系统。

1. 需求分析

在开始代码编写之前,我们需要明确系统的需求。基于FPGA和M4内核的特性,我们假设以下应用场景:

  • 高速数据采集与处理: 通过FPGA采集高速传感器数据(如ADC),并在FPGA内部进行预处理(如滤波、FFT),然后将处理结果传输给M4内核。
  • 实时控制: M4内核负责系统的整体控制,如控制电机、LED显示、与上位机通信等。
  • 用户交互: 通过按键、数码管等进行简单的用户交互。
  • 扩展性: 系统架构应支持未来添加新的模块和功能。

2. 系统架构设计

为了实现上述需求,我将采用分层架构,将系统划分为以下几个层次:

  • 硬件抽象层 (HAL): 提供对硬件资源的抽象接口,如GPIO、ADC、UART、SPI、I2C等。
  • FPGA加速层 (FAL): 提供在FPGA内部实现的加速模块的接口,如高速数据采集和预处理。
  • 服务层 (Services): 提供各种服务,如数据处理、传感器驱动、控制算法、通信协议等。
  • 应用层 (Application): 系统的具体应用逻辑,如数据采集、处理和展示、控制等。

2.1 代码结构

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
Project_G1/
├── inc/ # 头文件目录
│ ├── hal/ # 硬件抽象层头文件
│ │ ├── gpio.h
│ │ ├── adc.h
│ │ ├── uart.h
│ │ ├── spi.h
│ │ ├── i2c.h
│ │ ├── timer.h
│ │ └── ...
│ ├── fal/ # FPGA加速层头文件
│ │ ├── data_acq.h
│ │ ├── processing.h
│ │ └── ...
│ ├── services/ # 服务层头文件
│ │ ├── sensor.h
│ │ ├── control.h
│ │ ├── comm.h
│ │ ├── utils.h
│ │ └── ...
│ └── app/ # 应用层头文件
│ ├── main.h
│ └── ...
├── src/ # 源文件目录
│ ├── hal/ # 硬件抽象层源文件
│ │ ├── gpio.c
│ │ ├── adc.c
│ │ ├── uart.c
│ │ ├── spi.c
│ │ ├── i2c.c
│ │ ├── timer.c
│ │ └── ...
│ ├── fal/ # FPGA加速层源文件
│ │ ├── data_acq.c
│ │ ├── processing.c
│ │ └── ...
│ ├── services/ # 服务层源文件
│ │ ├── sensor.c
│ │ ├── control.c
│ │ ├── comm.c
│ │ ├── utils.c
│ │ └── ...
│ └── app/ # 应用层源文件
│ ├── main.c
│ └── ...
├── lib/ # 第三方库
│ └── ...
├── bsp/ # 板级支持包(BSP),包含GD32的头文件和启动代码
│ ├── gd32f30x/
│ │ ├── inc/
│ │ └── src/
│ ├── startup/
│ │ └── startup_gd32f30x.s
│ └── system_gd32f30x.c
├── doc/ # 文档
│ └── ...
├── tools/ # 工具脚本和配置文件
│ └── ...
├── CMakeLists.txt # CMake 构建文件
└── .gitignore

3. 技术选型

  • 编程语言: C (为主)
  • 开发工具: GCC,GDB,OpenOCD(GD32),Vivado/Gowin EDA(FPGA)
  • 构建系统: CMake
  • 版本控制: Git

4. 代码实现 (C)

以下代码将展示上述架构的实现,包括HAL层、FAL层、服务层和应用层的一些关键模块。

4.1 HAL层 (Hardware Abstraction Layer)

  • hal/gpio.h
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
#ifndef __GPIO_H__
#define __GPIO_H__

#include <stdint.h>
#include "gd32f30x.h" // 包含GD32的寄存器定义

typedef enum {
GPIO_MODE_INPUT,
GPIO_MODE_OUTPUT,
GPIO_MODE_AF
} gpio_mode_t;

typedef enum {
GPIO_SPEED_50MHZ,
GPIO_SPEED_2MHZ,
GPIO_SPEED_10MHZ
} gpio_speed_t;

typedef enum {
GPIO_PUPD_NONE,
GPIO_PUPD_UP,
GPIO_PUPD_DOWN
} gpio_pupd_t;

typedef enum {
GPIO_OUTPUT_PP, //推挽输出
GPIO_OUTPUT_OD //开漏输出
} gpio_output_t;


typedef struct {
uint32_t pin; // GPIO引脚
gpio_mode_t mode; // GPIO模式
gpio_speed_t speed; // GPIO速度
gpio_pupd_t pupd; // 上下拉模式
gpio_output_t outType; // 输出类型
} gpio_config_t;



void gpio_init(gpio_config_t *config, uint32_t port);
void gpio_write(uint32_t port, uint32_t pin, uint8_t value);
uint8_t gpio_read(uint32_t port, uint32_t pin);
void gpio_toggle(uint32_t port,uint32_t pin);
#endif
  • hal/gpio.c
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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#include "hal/gpio.h"

// 定义端口和引脚对应的GPIO寄存器地址 (基于GD32F303)
#define GPIOA_ADDR 0x40010800
#define GPIOB_ADDR 0x40010C00
#define GPIOC_ADDR 0x40011000
#define GPIOD_ADDR 0x40011400
#define GPIOE_ADDR 0x40011800
#define GPIOF_ADDR 0x40011C00
#define GPIOG_ADDR 0x40012000

#define GPIO_CRL_OFFSET 0x00
#define GPIO_CRH_OFFSET 0x04
#define GPIO_IDR_OFFSET 0x08
#define GPIO_ODR_OFFSET 0x0C
#define GPIO_BSRR_OFFSET 0x10
#define GPIO_BRR_OFFSET 0x14
#define GPIO_LCKR_OFFSET 0x18

static void RCC_EnableGPIO(uint32_t port)
{
if(port == GPIOA_ADDR) { RCC_APB2ENR |= RCC_APB2ENR_IOPAEN; }
else if(port == GPIOB_ADDR) { RCC_APB2ENR |= RCC_APB2ENR_IOPBEN; }
else if(port == GPIOC_ADDR) { RCC_APB2ENR |= RCC_APB2ENR_IOPCEN; }
else if(port == GPIOD_ADDR) { RCC_APB2ENR |= RCC_APB2ENR_IOPDEN; }
else if(port == GPIOE_ADDR) { RCC_APB2ENR |= RCC_APB2ENR_IOPEEN; }
else if(port == GPIOF_ADDR) { RCC_APB2ENR |= RCC_APB2ENR_IOPFEN; }
else if(port == GPIOG_ADDR) { RCC_APB2ENR |= RCC_APB2ENR_IOPGEN; }
}


static void GPIO_SetMode(uint32_t port, uint32_t pin, gpio_config_t *config)
{
volatile uint32_t *CR = (pin < 8) ? (volatile uint32_t*)(port + GPIO_CRL_OFFSET) : (volatile uint32_t*)(port + GPIO_CRH_OFFSET);
uint32_t offset = (pin < 8) ? (pin * 4) : ((pin - 8) * 4);
uint32_t mode = 0;

if (config->mode == GPIO_MODE_INPUT)
{
mode = (config->pupd == GPIO_PUPD_UP) ? 0x08 : (config->pupd == GPIO_PUPD_DOWN ? 0x04 : 0x00);
*CR &= ~(0x0f << offset); //清空原来的设置
*CR |= mode << offset; //配置输入模式
}
else if (config->mode == GPIO_MODE_OUTPUT)
{

if(config->outType == GPIO_OUTPUT_PP) {
mode = 0x01;
}
else{
mode = 0x05;
}
mode |= (config->speed == GPIO_SPEED_50MHZ ? 0x03 << 2 : config->speed == GPIO_SPEED_2MHZ ? 0x01 << 2 : 0x02 << 2) ;
*CR &= ~(0x0f << offset);
*CR |= mode << offset;

}
else if(config->mode == GPIO_MODE_AF)
{

if(config->outType == GPIO_OUTPUT_PP) {
mode = 0x0a;
} else{
mode = 0x0b;
}
mode |= (config->speed == GPIO_SPEED_50MHZ ? 0x03 << 2 : config->speed == GPIO_SPEED_2MHZ ? 0x01 << 2 : 0x02 << 2) ;
*CR &= ~(0x0f << offset);
*CR |= mode << offset;
}
}



void gpio_init(gpio_config_t *config, uint32_t port) {
RCC_EnableGPIO(port);
GPIO_SetMode(port,config->pin,config);
}

void gpio_write(uint32_t port, uint32_t pin, uint8_t value) {
volatile uint32_t *ODR = (volatile uint32_t*)(port + GPIO_ODR_OFFSET);

if (value)
{
*ODR |= (1 << pin);
}
else
{
*ODR &= ~(1 << pin);
}
}

uint8_t gpio_read(uint32_t port, uint32_t pin) {
volatile uint32_t *IDR = (volatile uint32_t*)(port + GPIO_IDR_OFFSET);
return (*IDR >> pin) & 0x1;
}
void gpio_toggle(uint32_t port,uint32_t pin){

volatile uint32_t *ODR = (volatile uint32_t*)(port + GPIO_ODR_OFFSET);

*ODR ^= (1<<pin);
}

  • hal/adc.h
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
#ifndef __ADC_H__
#define __ADC_H__

#include <stdint.h>
#include "gd32f30x.h" // 包含GD32的寄存器定义


typedef enum
{
ADC_RESOLUTION_12BIT,
ADC_RESOLUTION_10BIT,
ADC_RESOLUTION_8BIT,
ADC_RESOLUTION_6BIT,
} adc_resolution_t;


typedef struct
{
uint32_t channel;
adc_resolution_t resolution;
uint8_t sample_time; //采样时间
} adc_config_t;

void adc_init(adc_config_t *config);
uint16_t adc_read(uint8_t channel);



#endif
  • hal/adc.c
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
75
76
77
78
79
80
81
82
83
84
85
86
#include "hal/adc.h"

#define ADC1_ADDR 0x40012400
#define ADC_CTL0_OFFSET 0x00
#define ADC_CTL1_OFFSET 0x04
#define ADC_SAMPT0_OFFSET 0x08
#define ADC_SAMPT1_OFFSET 0x0C
#define ADC_OSTR_OFFSET 0x10
#define ADC_RDATA_OFFSET 0x14
#define ADC_WDATA_OFFSET 0x18
#define ADC_LST0_OFFSET 0x28
#define ADC_LST1_OFFSET 0x2C
#define ADC_LST2_OFFSET 0x30
#define ADC_LST3_OFFSET 0x34


static void RCC_EnableADC()
{
RCC_APB2ENR |= RCC_APB2ENR_ADC1EN;
}
static void ADC_SetResolution(adc_resolution_t resolution)
{

volatile uint32_t *CTL0 = (volatile uint32_t *)(ADC1_ADDR + ADC_CTL0_OFFSET);
*CTL0 &= ~(ADC_CTL0_ADCRES_MASK); // 清除分辨率配置
if (resolution == ADC_RESOLUTION_12BIT)
{
*CTL0 |= ADC_CTL0_ADCRES_12BIT;
}
else if (resolution == ADC_RESOLUTION_10BIT)
{
*CTL0 |= ADC_CTL0_ADCRES_10BIT;
}
else if (resolution == ADC_RESOLUTION_8BIT)
{
*CTL0 |= ADC_CTL0_ADCRES_8BIT;
}
else if (resolution == ADC_RESOLUTION_6BIT)
{
*CTL0 |= ADC_CTL0_ADCRES_6BIT;
}
}
static void ADC_ConfigChannel(uint8_t channel, uint8_t sample_time)
{
volatile uint32_t *SAMPT0 = (volatile uint32_t *)(ADC1_ADDR + ADC_SAMPT0_OFFSET);
volatile uint32_t *SAMPT1 = (volatile uint32_t *)(ADC1_ADDR + ADC_SAMPT1_OFFSET);
volatile uint32_t *LST0 = (volatile uint32_t *)(ADC1_ADDR + ADC_LST0_OFFSET);

if (channel <= 9)
{
*SAMPT0 &= ~(0x07 << (channel * 3));
*SAMPT0 |= (sample_time << (channel * 3));
}
else if(channel <= 17){
*SAMPT1 &= ~(0x07 << ((channel-10) * 3));
*SAMPT1 |= (sample_time << ((channel-10) * 3));
}


*LST0 &= ~(0x1F << (0 * 5)); //清空之前的配置
*LST0 |= (channel << (0 * 5)); //配置通道

}
void adc_init(adc_config_t *config)
{
RCC_EnableADC();
ADC_SetResolution(config->resolution);
ADC_ConfigChannel(config->channel,config->sample_time);

volatile uint32_t *CTL0 = (volatile uint32_t *)(ADC1_ADDR + ADC_CTL0_OFFSET);
*CTL0 |= ADC_CTL0_ADCON; //使能ADC

}
uint16_t adc_read(uint8_t channel)
{

volatile uint32_t *CTL1 = (volatile uint32_t *)(ADC1_ADDR + ADC_CTL1_OFFSET);
volatile uint32_t *CTL0 = (volatile uint32_t *)(ADC1_ADDR + ADC_CTL0_OFFSET);
volatile uint32_t *RDATA = (volatile uint32_t *)(ADC1_ADDR + ADC_RDATA_OFFSET);

*CTL1 |= ADC_CTL1_SWRCST; //启动转换
while (!(*CTL0 & ADC_CTL0_EOC)); // 等待转换完成

return (uint16_t)*RDATA;
}

  • hal/uart.h (简略版)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#ifndef __UART_H__
#define __UART_H__

#include <stdint.h>
#include "gd32f30x.h" // 包含GD32的寄存器定义

typedef struct {
uint32_t baudrate;
uint8_t parity; // 0: None, 1: Even, 2: Odd
uint8_t stopbits; // 1 or 2
uint8_t databits; // 8 or 9
} uart_config_t;

void uart_init(uart_config_t *config,uint32_t uart);
void uart_send_byte(uint32_t uart, uint8_t data);
void uart_send_string(uint32_t uart, char *str);
uint8_t uart_receive_byte(uint32_t uart);
void uart_receive_string(uint32_t uart, char *buffer, uint16_t len);


#endif
  • hal/uart.c (简略版)
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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#include "hal/uart.h"

#define UART0_ADDR 0x40004400
#define UART1_ADDR 0x40004800
#define UART2_ADDR 0x40004C00

#define UART_CTL0_OFFSET 0x00
#define UART_CTL1_OFFSET 0x04
#define UART_CTL2_OFFSET 0x08
#define UART_BAUD_OFFSET 0x0C
#define UART_STAT_OFFSET 0x10
#define UART_DATA_OFFSET 0x14
#define UART_GP_OFFSET 0x18

// 定义波特率计算公式 (基于GD32F303)
#define APB1_CLOCK 72000000 //假设APB1时钟为 72MHz
#define APB2_CLOCK 72000000
#define UART_DIV(baudrate,clk) ((uint32_t)((float)(clk) / (16.0 * (float)baudrate) + 0.5))

static void RCC_EnableUART(uint32_t uart)
{
if(uart == UART0_ADDR) { RCC_APB2ENR |= RCC_APB2ENR_AFIOEN | RCC_APB2ENR_UART0EN;}
else if (uart == UART1_ADDR) {RCC_APB1ENR |= RCC_APB1ENR_UART1EN; }
else if (uart == UART2_ADDR){RCC_APB1ENR |= RCC_APB1ENR_UART2EN;}

}
static void GPIO_ConfigUART(uint32_t uart)
{
gpio_config_t gpio_config;
if(uart == UART0_ADDR)
{
gpio_config.mode = GPIO_MODE_AF;
gpio_config.speed = GPIO_SPEED_50MHZ;
gpio_config.outType = GPIO_OUTPUT_PP;
gpio_config.pin = GPIO_PIN_9;
gpio_init(&gpio_config,GPIOA_ADDR); //TxD

gpio_config.pin = GPIO_PIN_10;
gpio_config.mode = GPIO_MODE_INPUT;
gpio_config.pupd = GPIO_PUPD_UP;
gpio_init(&gpio_config,GPIOA_ADDR); //RxD
}
else if (uart == UART1_ADDR)
{
gpio_config.mode = GPIO_MODE_AF;
gpio_config.speed = GPIO_SPEED_50MHZ;
gpio_config.outType = GPIO_OUTPUT_PP;
gpio_config.pin = GPIO_PIN_9;
gpio_init(&gpio_config,GPIOB_ADDR);

gpio_config.pin = GPIO_PIN_10;
gpio_config.mode = GPIO_MODE_INPUT;
gpio_config.pupd = GPIO_PUPD_UP;
gpio_init(&gpio_config,GPIOB_ADDR);
}
else if(uart == UART2_ADDR){
gpio_config.mode = GPIO_MODE_AF;
gpio_config.speed = GPIO_SPEED_50MHZ;
gpio_config.outType = GPIO_OUTPUT_PP;
gpio_config.pin = GPIO_PIN_2;
gpio_init(&gpio_config,GPIOA_ADDR);

gpio_config.pin = GPIO_PIN_3;
gpio_config.mode = GPIO_MODE_INPUT;
gpio_config.pupd = GPIO_PUPD_UP;
gpio_init(&gpio_config,GPIOA_ADDR);
}

}


void uart_init(uart_config_t *config,uint32_t uart)
{
RCC_EnableUART(uart);
GPIO_ConfigUART(uart);

volatile uint32_t *CTL0 = (volatile uint32_t*)(uart + UART_CTL0_OFFSET);
volatile uint32_t *CTL1 = (volatile uint32_t*)(uart + UART_CTL1_OFFSET);
volatile uint32_t *BAUD = (volatile uint32_t*)(uart + UART_BAUD_OFFSET);

// 配置数据位,停止位,校验位
*CTL0 &= ~(UART_CTL0_WL | UART_CTL0_PCEN | UART_CTL0_STB);
if (config->databits == 9) { *CTL0 |= UART_CTL0_WL_9BIT; }
if(config->parity == 1) {*CTL0 |= UART_CTL0_PCEN | UART_CTL0_PCE;}
else if(config->parity == 2) { *CTL0 |= UART_CTL0_PCEN;}
if (config->stopbits == 2) { *CTL0 |= UART_CTL0_STB; }
// 配置波特率
*BAUD = UART_DIV(config->baudrate,(uart==UART0_ADDR)? APB2_CLOCK:APB1_CLOCK);


*CTL1 |= UART_CTL1_UEN | UART_CTL1_TEN | UART_CTL1_REN; // 使能 UART, 发送使能,接收使能

}

void uart_send_byte(uint32_t uart, uint8_t data)
{
volatile uint32_t *STAT = (volatile uint32_t*)(uart + UART_STAT_OFFSET);
volatile uint32_t *DATA = (volatile uint32_t*)(uart + UART_DATA_OFFSET);
while (!(*STAT & UART_STAT_TBE)); // 等待发送缓冲区空
*DATA = data;

}

void uart_send_string(uint32_t uart, char *str)
{
while (*str)
{
uart_send_byte(uart, *str++);
}
}
uint8_t uart_receive_byte(uint32_t uart)
{
volatile uint32_t *STAT = (volatile uint32_t*)(uart + UART_STAT_OFFSET);
volatile uint32_t *DATA = (volatile uint32_t*)(uart + UART_DATA_OFFSET);
while (!(*STAT & UART_STAT_RBNE)); // 等待接收缓冲区非空
return (uint8_t)*DATA;
}
void uart_receive_string(uint32_t uart, char *buffer, uint16_t len)
{
for (uint16_t i = 0; i < len; i++) {
buffer[i] = uart_receive_byte(uart);
if (buffer[i] == '\0') {
break;
}
}
}
  • hal/timer.h (简略版)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#ifndef __TIMER_H__
#define __TIMER_H__

#include <stdint.h>
#include "gd32f30x.h" // 包含GD32的寄存器定义

typedef enum {
TIMER_MODE_ONE_SHOT,
TIMER_MODE_CONTINUOUS
} timer_mode_t;


typedef struct {
uint32_t prescaler;
uint32_t period;
timer_mode_t mode;
} timer_config_t;
void timer_init(timer_config_t *config,uint32_t timer);
void timer_start(uint32_t timer);
void timer_stop(uint32_t timer);
void timer_enable_interrupt(uint32_t timer);
void timer_disable_interrupt(uint32_t timer);
void timer_clear_flag(uint32_t timer);
#endif
  • hal/timer.c (简略版)
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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#include "hal/timer.h"
#define TIMER0_ADDR 0x40012C00
#define TIMER1_ADDR 0x40012800
#define TIMER2_ADDR 0x40000000
#define TIMER3_ADDR 0x40000400

#define TIMER_CTL0_OFFSET 0x00
#define TIMER_CTL1_OFFSET 0x04
#define TIMER_SMCFG_OFFSET 0x08
#define TIMER_DMAINTEN_OFFSET 0x0C
#define TIMER_INTF_OFFSET 0x10
#define TIMER_SWINT_OFFSET 0x14
#define TIMER_PSC_OFFSET 0x28
#define TIMER_CAR_OFFSET 0x2C
#define TIMER_CNT_OFFSET 0x30
#define TIMER_CH0CV_OFFSET 0x34
#define TIMER_CH1CV_OFFSET 0x38
#define TIMER_CH2CV_OFFSET 0x3C
#define TIMER_CH3CV_OFFSET 0x40

static void RCC_EnableTimer(uint32_t timer)
{
if(timer == TIMER0_ADDR) { RCC_APB2ENR |= RCC_APB2ENR_TIMER0EN; }
else if (timer == TIMER1_ADDR) {RCC_APB2ENR |= RCC_APB2ENR_TIMER1EN;}
else if (timer == TIMER2_ADDR) {RCC_APB1ENR |= RCC_APB1ENR_TIMER2EN;}
else if (timer == TIMER3_ADDR) {RCC_APB1ENR |= RCC_APB1ENR_TIMER3EN;}
}

void timer_init(timer_config_t *config,uint32_t timer){
RCC_EnableTimer(timer);
volatile uint32_t *CTL0 = (volatile uint32_t *)(timer + TIMER_CTL0_OFFSET);
volatile uint32_t *PSC = (volatile uint32_t *)(timer + TIMER_PSC_OFFSET);
volatile uint32_t *CAR = (volatile uint32_t *)(timer + TIMER_CAR_OFFSET);

*PSC = config->prescaler;
*CAR = config->period;

*CTL0 &= ~(TIMER_CTL0_OPM);
if (config->mode == TIMER_MODE_ONE_SHOT) {
*CTL0 |= TIMER_CTL0_OPM;
}

}

void timer_start(uint32_t timer)
{
volatile uint32_t *CTL0 = (volatile uint32_t *)(timer + TIMER_CTL0_OFFSET);
*CTL0 |= TIMER_CTL0_CEN;
}
void timer_stop(uint32_t timer)
{
volatile uint32_t *CTL0 = (volatile uint32_t *)(timer + TIMER_CTL0_OFFSET);
*CTL0 &= ~TIMER_CTL0_CEN;
}
void timer_enable_interrupt(uint32_t timer){
volatile uint32_t *DMAINTEN = (volatile uint32_t *)(timer + TIMER_DMAINTEN_OFFSET);
*DMAINTEN |= TIMER_DMAINTEN_UPIE;
//开启NVIC中断
if (timer == TIMER0_ADDR) {
NVIC_EnableIRQ(TIMER0_IRQn);
}else if(timer == TIMER1_ADDR) {
NVIC_EnableIRQ(TIMER1_IRQn);
}else if (timer == TIMER2_ADDR) {
NVIC_EnableIRQ(TIMER2_IRQn);
}
else if (timer == TIMER3_ADDR) {
NVIC_EnableIRQ(TIMER3_IRQn);
}
}
void timer_disable_interrupt(uint32_t timer){
volatile uint32_t *DMAINTEN = (volatile uint32_t *)(timer + TIMER_DMAINTEN_OFFSET);
*DMAINTEN &= ~TIMER_DMAINTEN_UPIE;
if (timer == TIMER0_ADDR) {
NVIC_DisableIRQ(TIMER0_IRQn);
}else if(timer == TIMER1_ADDR) {
NVIC_DisableIRQ(TIMER1_IRQn);
}else if (timer == TIMER2_ADDR) {
NVIC_DisableIRQ(TIMER2_IRQn);
}
else if (timer == TIMER3_ADDR) {
NVIC_DisableIRQ(TIMER3_IRQn);
}
}
void timer_clear_flag(uint32_t timer){
volatile uint32_t *INTF = (volatile uint32_t *)(timer + TIMER_INTF_OFFSET);
*INTF &= ~(TIMER_INTF_UPIF);
}

4.2 FAL层 (FPGA Acceleration Layer)

由于FPGA代码需要使用硬件描述语言(Verilog/VHDL)进行编写,这里只展示对应的头文件和C接口函数,FPGA的实际实现需要使用对应的FPGA开发工具进行。

  • fal/data_acq.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#ifndef __DATA_ACQ_H__
#define __DATA_ACQ_H__

#include <stdint.h>

#define DATA_BUFFER_SIZE 1024

typedef struct {
uint16_t buffer[DATA_BUFFER_SIZE];
uint32_t count;
uint8_t full;
} data_buffer_t;

extern data_buffer_t data_acq_buffer;
void data_acq_init(void);
void data_acq_start(void);
void data_acq_stop(void);
uint16_t data_acq_read_sample(void);

#endif
  • fal/data_acq.c
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
#include "fal/data_acq.h"

data_buffer_t data_acq_buffer = {0};

void data_acq_init(void) {
// 初始化 FPGA 模块,例如配置 ADC 和 DMA
// 代码可能需要通过 SPI/I2C 与 FPGA 进行通信
}

void data_acq_start(void) {
// 启动 FPGA 模块的数据采集
}

void data_acq_stop(void) {
// 停止 FPGA 模块的数据采集
}
uint16_t data_acq_read_sample(void){
// 从 FPGA 读取一个ADC采样值。
if(data_acq_buffer.full) {
data_acq_buffer.count = 0;
data_acq_buffer.full = 0;

}
if(data_acq_buffer.count >= DATA_BUFFER_SIZE){
data_acq_buffer.full = 1;
return 0;
}
return data_acq_buffer.buffer[data_acq_buffer.count++];
}

  • fal/processing.h

    1
    2
    3
    4
    5
    6
    7
    8
    9
    #ifndef __PROCESSING_H__
    #define __PROCESSING_H__
    #include <stdint.h>
    #include "fal/data_acq.h"

    void processing_init(void);
    void processing_execute(data_buffer_t * input_buffer, uint32_t dataSize, uint16_t *output_buffer);

    #endif
  • fal/processing.c

1
2
3
4
5
6
7
8
9
10
11
12
13
#include "fal/processing.h"

void processing_init(void)
{
//初始化FPGA数据处理模块
}

void processing_execute(data_buffer_t * input_buffer, uint32_t dataSize, uint16_t *output_buffer)
{
// 调用FPGA内部的模块处理数据
// FPGA会执行滤波或者FFT等
// 将结果存储在 output_buffer
}

4.3 Services层 (服务层)

  • services/sensor.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#ifndef __SENSOR_H__
#define __SENSOR_H__

#include <stdint.h>
#include "hal/adc.h"
typedef struct {
uint16_t value;
float scaled_value;
} sensor_data_t;
typedef struct {
adc_config_t config;
}sensor_config_t;
void sensor_init(sensor_config_t *config);
sensor_data_t sensor_read_data(void);

#endif

欢迎关注我的其它发布渠道