feat(pl,drv): 添加了外部信号屏蔽相机触发的机制

1. pl端的encoder模块实现了可选的外部复位信号
2. pl端修改encoder模块的ENCODER_CR寄存器复位值,为仅限内部复位以及内部默认处于复位状态
3. 驱动层实现外部复位的开启和关闭功能,驱动open时退出默认的复位清零状态
   由于驱动程序已在open时退出复位状态,应用程序可不做更改,驱动程序close后不会自动切换回复位状态
4. 更新了驱动测试应用程序
This commit is contained in:
Miaow 2023-04-26 21:21:40 +08:00
parent c21a5d8371
commit 4ecbc6a0ba
18 changed files with 137 additions and 64 deletions

View File

@ -9,10 +9,10 @@
IO扩展版提供了
- 1个12V电源输入
- 4个相机触发
- 4个相机触发本次项目为2个相机触发其余冗余
- 1个ZYNQ散热风扇接口
- 6个编码器或IO输入
- 8个阀板接口
- 6个编码器或IO输入本次项目为1个编码器输入、1个物体传感器输入其余冗余
- 8个阀板接口,本次项目没有用到
接线时12V电源连接到IO扩展板的电源接口阀板从左到右应连接在阀板接口1~6上相机线应连接相机触发接口`TRIG1`和对应的`GND`接口,编码器线应连接在编码器输入接口`E1`和对应的`GND`接口。注意底板不连接任何外部电源。
@ -45,7 +45,7 @@ IO扩展版提供了
- source为XME0724板子上运行的源程序
- liunx_app为Linux上运行的应用程序即业务逻辑
- linux_driver为Linux上的驱动用于控制自定义的PL端硬件
- linux_driver为Linux上的驱动用于控制自定义的PL端硬件其中drv_test结尾的目录为相应驱动模块的测试应用程序
- petalinux_config为petalinux工具在编译u-boot、kernel、rootfs前进行的配置
- petalinux_devicetree为本次自定义的Linux设备树文件部分其余设备树为自动生成的
- petalinux_hwdescription为petalinux所使用的硬件描述文件包含了vivado工程中的比特流等信息

Binary file not shown.

After

Width:  |  Height:  |  Size: 258 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 539 KiB

View File

@ -2,7 +2,7 @@
PL端主要由4个外设组成分别时**风扇控制器**(FAN)**编码和分频控制器**(ENCODER)**先入先出队列**(FIFO)**阀板控制器**(VALVE)。其中阀板控制器没有提供AXI接口因此并没有映射寄存器软件也无法进行控制。各个控制器的连接关系如下图所示。
![2](hardware_description.assets/system_arch.png)
![2](hardware_description.assets/system_arch.jpg)
由于开发板的PL端没有自带晶振所以4个外设由统一的同步时钟驱动时钟源来自PS端为200MHz软件不可修改。外部编码器信号输入**编码和分频控制器**,控制器根据软件设置的阀触发分频值和相机触发分频值对编码器信号进行分频,分频后的信号用于驱动喷阀动作和触发相机拍照。上位机的识别结果存储到**先入先出队列**中。
@ -31,14 +31,15 @@ ARM核上还开启AXI GP0接口与PL通信
## ENCODER模块
encoder模块主要接口为in_signal、out_signal_camera_a_posedge、out_signal_camera_b_posedge、out_signal_camera_c_posedge、out_signal_camera_d_posedge、out_signal_valve_posedge、out_signal_camera_a、out_signal_camera_b、out_signal_camera_c、out_signal_camera_d、out_signal_valve
encoder模块主要接口为in_signal、out_signal_camera_a_posedge、out_signal_camera_b_posedge、out_signal_camera_c_posedge、out_signal_camera_d_posedge、out_signal_valve_posedge、out_signal_camera_a、out_signal_camera_b、out_signal_camera_c、out_signal_camera_d、out_signal_valve、exrst_n
终于,我们重新实现了被老倪乱起八糟的需求搞的几乎奔溃的模块
终于,我们重新实现了被老倪乱起八糟的需求搞的几乎奔溃的模块,现在这个模块已经比较简洁了
1. in_signal接口与外部编码器相连接收外部编码器信号
2. out_signal_camera_a到d最多课用于触发共4个相机
3. out_signal_camera_posedge_a到d为上述信号的上升沿其中out_signal_camera_posedge_a控制FIFO的读出
5. out_signal_valve_posedge为out_signal_valve的上升沿驱动**阀板控制器**动作
4. out_signal_valve_posedge为out_signal_valve的上升沿驱动**阀板控制器**动作
5. exrst_n为可选的外部复位清零信号可用于连接物体传感器根据需要屏蔽相机触发输出
ENCODER模块输入输出频率的详细计算方式和寄存器说明见[doc/pl_reference_mannual.md](pl_reference_mannual.md)中的ENCODER控制器部分

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 84 KiB

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 258 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 539 KiB

View File

@ -6,7 +6,7 @@
PL端主要由4个外设组成分别时**风扇控制器**(FAN)**编码和分频控制器**(ENCODER)**先入先出队列**(FIFO)和**阀板控制器**(VALVE)。其中阀板控制器没有提供AXI接口因此并没有映射寄存器软件也无法进行控制。各个控制器的连接关系如下图所示。
![system_arch](pl_reference_mannual.assets/system_arch.png)
![system_arch](pl_reference_mannual.assets/system_arch.jpg)
4个外设由统一的同步时钟驱动时钟源来自PS端为200MHz软件不可修改。外部编码器信号输入**编码和分频控制器**,控制器根据软件设置的阀触发分频值和相机触发分频值对编码器信号进行分频。为同步触发相机和移出队列,**先入先出队列**在相机触发同时输出一个数据,即**先入先出队列**读信号和相机触发共用同一个信号。而由于电磁阀的物理特性导致电磁阀无法以触发相机的频率进行开关,因此**阀板控制器**对先入先出队列输出总线上的数据进行重采样,即按照**编码和分频控制器**输出的阀触发信号更新并转换为阀板协议,输出电磁阀的状态。
@ -74,13 +74,13 @@ FAN寄存器可映射为32位可寻址寄存器如下表所述
### ENCODER简介
ENCODER模块主要用于实现编码器计数以及对编码器脉冲进行分频分频后的脉冲信号输出给相机和阀板并且能控制FIFO模块的读操作将数据加载到AXI数据总线上。该模块包括1个控制寄存器 (ENCODER_CR)、阀触发分频寄存器 (ENCODER_VDIVR)、相机触发分频寄存器 (ENCODER_CDIVR)。
ENCODER模块主要用于实现编码器计数以及对编码器脉冲进行分频分频后的脉冲信号输出给相机。该模块包括1个控制寄存器 (ENCODER_CR)、阀触发分频寄存器 (ENCODER_VDIVR)、相机触发分频寄存器 (ENCODER_CDIVR)。
### ENCODER主要特性
- 独立设置对相机和喷阀的分频系数
- 内外两种触发模式选择
- 清空功能
- 可选的外部清零方式
### ENCODER功能说明
@ -98,16 +98,17 @@ ENCODER模块的寄存器主要有控制寄存器 (ENCODER_CR)、阀触发分频
#### ENCODER控制寄存器 (ENCODER_CR)
偏移地址: 0x00<br/>复位值: 0x0000 0000
偏移地址: 0x00<br/>复位值: 0x0000 0009
![ ](pl_reference_mannual.assets/encoder_cr.svg)
| **Field** | **Description** |
| :---------- | :----------------------------------------------------------- |
| 位31:3 保留 | 必须保持复位值 |
| 位31:4 保留 | 必须保持复位值 |
| 位3 **ICO** | 仅限内部清除缓存 (Internal Clear Only)<br /> 0: 同时允许由外部输入**Ex CLR**和清除缓存位**CLR**控制进入清零状态<br /> 清零状态见位**CLR**的描述;外部输入为高时,退出清零状态<br /> 1: 仅限内部信号清除缓存 |
| 位2 **VTS** | 内部触发信号 (Virtual Triggle Signal)<br /> **MOD**位置1时由软件写入将该位信号直接充当触发信号<br /> 0: 低电平<br /> 1: 高电平 |
| 位1 **MOD** | 模式选择 (Mode)<br /> 0: 外部触发模式,外部触发编码器转动<br /> 1: 内部触发模式,软件模拟触发信号 |
| 位0 **CLR** | 清除缓存 (Clear)<br /> 0: 正常工作 <br /> 1: 清除编码和分频控制器内部的分频计数值不影响VDIV和CDIV<br /> 注意: 程序置位该位后后需再写入0使计数器退出清零状态正常工作 |
| 位0 **CLR** | 清除缓存 (Clear)<br /> 0: 正常工作 <br /> 1: 清除编码和分频控制器内部的分频计数值,不影响ENCODER_VDIVRxENCODER_CDIVR<br /> 注意: 程序置位该位后后需再写入0使计数器退出清零状态正常工作 |
#### ENCODER阀触发分频寄存器 (ENCODER_VDIVR)

View File

@ -1 +1 @@
1.3
1.4

View File

@ -18,6 +18,9 @@
#define ENCODER_CMD_INPUT_MODE_EXTERNEL 100
#define ENCODER_CMD_INPUT_MODE_INTERNEL 101
#define ENCODER_CMD_CLEAR_MODE_BOTH 200
#define ENCODER_CMD_CLEAR_MODE_INTERNAL 201
/*
*
*/
@ -31,6 +34,7 @@
#define ENCODER_REG_6_OFFSET 0x00000018
#define ENCODER_REG_7_OFFSET 0x0000001C
#define ENCODER_CR_ICO_MASK ((u32)(1 << 3)) // 仅限内部清除缓存 (Iternal Clear Only) 0: 允许外部输入和CLR位共同控制清除缓存1 仅允许CLR位清除缓存
#define ENCODER_CR_VTS_MASK ((u32)(1 << 2)) // 内部触发信号 (Virtual Triggle Signal) MOD位置1时由上位机软件写入将该位信号作为触发信号
#define ENCODER_CR_MOD_MASK ((u32)(1 << 1)) // 模式选择 (Mode) 0: 外部触发模式,外部触发编码器转动, 1: 内部触发模式,上位机软件模拟触发信号
#define ENCODER_CR_CLR_MASK ((u32)(1 << 0)) // 清除缓存 (Clear) 清除编码和分频控制器内部的分频计数值不影响VDIV和CDIV
@ -72,6 +76,8 @@ static struct encoder_dev encoder;
*/
static int encoder_open(struct inode *inode, struct file *filp)
{
u32 data = readl(encoder_cr_addr);
writel(data & ~ENCODER_CR_CLR_MASK, encoder_cr_addr);
return 0;
}
@ -95,7 +101,7 @@ static ssize_t encoder_write(struct file *filp, const char __user *buf, size_t c
.camera_c_divide_value = 0,
.camera_d_divide_value = 0,
};
if (cnt != sizeof(kern_buf))
if (cnt != sizeof(kern_buf))
{
printk(KERN_ERR "encoder write: cnt error, cnt=%d", cnt);
return -EFAULT;
@ -107,11 +113,10 @@ static ssize_t encoder_write(struct file *filp, const char __user *buf, size_t c
return -EFAULT;
}
// 最小分频值为2
if (kern_buf.valve_divide_value < 2 || kern_buf.camera_a_divide_value < 2 ||
kern_buf.camera_b_divide_value < 2 || kern_buf.camera_c_divide_value < 2 ||
kern_buf.camera_d_divide_value < 2)
if (kern_buf.valve_divide_value < 2 || kern_buf.camera_a_divide_value < 2 ||
kern_buf.camera_b_divide_value < 2 || kern_buf.camera_c_divide_value < 2 ||
kern_buf.camera_d_divide_value < 2)
return -EFAULT;
// 写入0后清除ENCODER内部计数器缓存清除
data = readl(encoder_cr_addr);
@ -136,6 +141,8 @@ static ssize_t encoder_write(struct file *filp, const char __user *buf, size_t c
*/
static int encoder_release(struct inode *inode, struct file *filp)
{
u32 data = readl(encoder_cr_addr);
writel(data | ENCODER_CR_CLR_MASK, encoder_cr_addr);
return 0;
}
@ -162,14 +169,14 @@ static long encoder_ioctl(struct file *fp, unsigned int cmd, unsigned long tmp)
else if (cmd_parsed == ENCODER_CMD_INPUT_MODE_INTERNEL)
{
// 设为内部触发模式
writel(data | (u32)(1 << 1), encoder_cr_addr);
writel(data | ENCODER_CR_MOD_MASK, encoder_cr_addr);
}
else if (cmd_parsed == ENCODER_CMD_FUNCTION_VIRT_INPUT)
{
int i;
// 虚拟触发tmp为周期数
// 1. 设为内部触发模式
writel(data | (u32)(1 << 1), encoder_cr_addr);
writel(data | ENCODER_CR_MOD_MASK, encoder_cr_addr);
// 2. 产生虚拟的高低电平
for (i = 0; i < tmp; i++)
@ -181,7 +188,16 @@ static long encoder_ioctl(struct file *fp, unsigned int cmd, unsigned long tmp)
// 3. 恢复为原来的状态和模式
writel(data, encoder_cr_addr);
}
else if (cmd_parsed == ENCODER_CMD_CLEAR_MODE_INTERNAL)
{
// 设为允许内部和外部信号清除缓存
writel(data & ~ENCODER_CR_ICO_MASK, encoder_cr_addr);
}
else if (cmd_parsed == ENCODER_CMD_CLEAR_MODE_BOTH)
{
// 设为仅允许内部清除缓存
writel(data | ENCODER_CR_ICO_MASK, encoder_cr_addr);
}
return 0;
}
@ -206,7 +222,6 @@ static int __init encoder_init(void)
encoder_cdivrc_addr = ioremap(ENCODER_REG_BASE + ENCODER_REG_4_OFFSET, 4);
encoder_cdivrd_addr = ioremap(ENCODER_REG_BASE + ENCODER_REG_5_OFFSET, 4);
// 创建设备号
if (encoder.major)
{
@ -253,10 +268,10 @@ static int __init encoder_init(void)
data = readl(encoder_cr_addr);
writel(data & ~ENCODER_CR_CLR_MASK, encoder_cr_addr); // 清除硬件计数器缓存
writel(1000, encoder_vdivr_addr); // 设置阀触发分频
writel(1000, encoder_cdivra_addr); // 设置相机a触发分频
writel(1000, encoder_cdivrb_addr); // 设置相机b触发分频
writel(1000, encoder_cdivrc_addr); // 设置相机c触发分频
writel(1000, encoder_cdivrd_addr); // 设置相机d触发分频
writel(1000, encoder_cdivra_addr); // 设置相机a触发分频
writel(1000, encoder_cdivrb_addr); // 设置相机b触发分频
writel(1000, encoder_cdivrc_addr); // 设置相机c触发分频
writel(1000, encoder_cdivrd_addr); // 设置相机d触发分频
writel(data | ENCODER_CR_CLR_MASK, encoder_cr_addr); // 清除完毕
return 0;

View File

@ -1,17 +1,19 @@
/**
* @file encoder_dev.c
* @brief Manage the hardware encoder unit
* @author miaow (3703781@qq.com)
* @version 1.0
* @date 2022/06/11
* @author miaow, lyz (3703781@qq.com)
* @version 0.11
* @date 2022/04/26
* @mainpage github.com/NanjingForestryUniversity
*
* @copyright Copyright (c) 2022 miaow
*
*
* @copyright Copyright (c) 2023 miaow, lyz
*
* @par Changelog:
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2022/06/11 <td>0.9 <td>Miaow <td>Write this module
* <tr><td>2022/06/11 <td>0.9 <td>Miaow <td>Write this module
* <tr><td>2022/04/11 <td>0.10 <td>lyz <td>Add seprate dividers up to 4 cameras
* <tr><td>2023/04/26 <td>0.11 <td>Miaow <td>Add Clear mode
* </table>
*/
@ -31,7 +33,8 @@
static int encoder_dev_fd = -1;
static char perror_buffer[128];
static struct {
static struct
{
uint32_t valve_divide_value;
uint32_t camera_a_divide_value;
uint32_t camera_b_divide_value;
@ -48,6 +51,7 @@ int encoder_dev_init()
{
encoder_dev_fd = open(ENCODER_DEV_PATH, O_RDWR);
ON_ERROR_RET(encoder_dev_fd, "", "", -1);
encoder_dev_set_divide(100, 100, 100, 100, 100);
return 0;
}
@ -55,22 +59,33 @@ int encoder_dev_init()
* @brief Set the two divider in the hareware encoder unit.
* @param valve_divide the frequency division factor between the encoder signal and valve output
* Set ENCODER_DEV_DIVIDE_NOT_TO_SET to skip changing the division facter
* @param camera_divide the frequency division factor between the encoder signal and camera triggle signal
* @param camera_a_divide the frequency division factor between the encoder signal and camera a triggle signal
* Set ENCODER_DEV_DIVIDE_NOT_TO_SET to skip changing the division facter
* @param camera_b_divide the frequency division factor between the encoder signal and camera b triggle signal
* Set ENCODER_DEV_DIVIDE_NOT_TO_SET to skip changing the division facter
* @param camera_c_divide the frequency division factor between the encoder signal and camera c triggle signal
* Set ENCODER_DEV_DIVIDE_NOT_TO_SET to skip changing the division facter
* @param camera_d_divide the frequency division factor between the encoder signal and camera d triggle signal
* Set ENCODER_DEV_DIVIDE_NOT_TO_SET to skip changing the division facter
*
* @return 0 - success, other - error
*/
int encoder_dev_set_divide(int valve_divide,
int camera_a_divide,
int camera_b_divide,
int camera_c_divide,
int camera_d_divide)
int encoder_dev_set_divide(int valve_divide,
int camera_a_divide,
int camera_b_divide,
int camera_c_divide,
int camera_d_divide)
{
encoder_dev_divide_value_structure.valve_divide_value = valve_divide;
encoder_dev_divide_value_structure.camera_a_divide_value = camera_a_divide;
encoder_dev_divide_value_structure.camera_b_divide_value = camera_b_divide;
encoder_dev_divide_value_structure.camera_c_divide_value = camera_c_divide;
encoder_dev_divide_value_structure.camera_d_divide_value = camera_d_divide;
if (valve_divide != ENCODER_DEV_DIVIDE_NOT_TO_SET)
encoder_dev_divide_value_structure.valve_divide_value = valve_divide;
if (camera_a_divide != ENCODER_DEV_DIVIDE_NOT_TO_SET)
encoder_dev_divide_value_structure.camera_a_divide_value = camera_a_divide;
if (camera_b_divide != ENCODER_DEV_DIVIDE_NOT_TO_SET)
encoder_dev_divide_value_structure.camera_b_divide_value = camera_b_divide;
if (camera_c_divide != ENCODER_DEV_DIVIDE_NOT_TO_SET)
encoder_dev_divide_value_structure.camera_c_divide_value = camera_c_divide;
if (camera_d_divide != ENCODER_DEV_DIVIDE_NOT_TO_SET)
encoder_dev_divide_value_structure.camera_d_divide_value = camera_d_divide;
ssize_t size = write(encoder_dev_fd, &encoder_dev_divide_value_structure, sizeof(encoder_dev_divide_value_structure));
int res = -(size != sizeof(encoder_dev_divide_value_structure));
ON_ERROR_RET(res, "size=", "", -1);
@ -95,7 +110,18 @@ int encoder_dev_virtual_trig(int count)
* @param mode ENCODER_TRIG_MODE_EXTERNEL for externally trig, or ENCODER_TRIG_MODE_INTERNEL for internally trig
* @return 0 - success, other - error
*/
int encoder_dev_set_trigmod(int mode)
int encoder_dev_set_trigmod(encoder_dev_trig_mode_enum mode)
{
int res = ioctl(encoder_dev_fd, _IOW('D', mode, int));
ON_ERROR_RET(res, "", "", -1);
return 0;
}
/**
* @brief Set the clr signal to internal or both external and internal.
* @return 0 - success, other - error
*/
int encoder_dev_set_clrmod(encoder_dev_clear_mode_enum mode)
{
int res = ioctl(encoder_dev_fd, _IOW('D', mode, int));
ON_ERROR_RET(res, "", "", -1);
@ -127,3 +153,4 @@ int encoder_dev_deinit()
ON_ERROR_RET(res, "", "", -1);
return 0;
}

View File

@ -1,16 +1,19 @@
/**
* @file encoder_dev.h
* @brief Manage the hardware encoder unit
* @author miaow (3703781@qq.com)
* @version 1.0
* @date 2022/06/11
* @author miaow, lzy (3703781@qq.com)
* @version 0.11
* @date 2022/04/26
* @mainpage github.com/NanjingForestryUniversity
*
* @copyright Copyright (c) 2022 miaow
* @copyright Copyright (c) 2023 miaow, lyz
*
* @par Changelog:
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2022/06/11 <td>0.9 <td>Miaow <td>Write this module
* <tr><td>2022/06/11 <td>0.9 <td>Miaow <td>Write this module
* <tr><td>2022/04/11 <td>0.10 <td>lyz <td>Add seprate dividers up to 4 cameras
* <tr><td>2023/04/26 <td>0.11 <td>Miaow <td>Add Clear mode
* </table>
*/
#ifndef __ENCODER_DEV_H
@ -22,8 +25,17 @@
#define ENCODER_DEV_DIVIDE_NOT_TO_SET 0
#define ENCODER_TRIG_MODE_EXTERNEL 100
#define ENCODER_TRIG_MODE_INTERNEL 101
typedef enum
{
ENCODER_TRIG_MODE_EXTERNEL = 100,
ENCODER_TRIG_MODE_INTERNEL = 101
} encoder_dev_trig_mode_enum;
typedef enum
{
ENCODER_CLEAR_MODE_BOTH = 200,
ENCODER_CLEAR_MODE_INTERNAL = 201
} encoder_dev_clear_mode_enum;
int encoder_dev_set_divide(int valve_divide,
int camera_a_divide,
@ -31,7 +43,8 @@ int encoder_dev_set_divide(int valve_divide,
int camera_c_divide,
int camera_d_divide);
int encoder_dev_flush(void);
int encoder_dev_set_trigmod(int mode);
int encoder_dev_set_trigmod(encoder_dev_trig_mode_enum mode);
int encoder_dev_set_clrmod(encoder_dev_clear_mode_enum mode);
int encoder_dev_virtual_trig(int count);
int encoder_dev_init(void);
int encoder_dev_deinit(void);

View File

@ -12,13 +12,28 @@ int main(int argc, char *argv[])
unsigned int a = 100, b = 100, c = 100, d = 100;
unsigned int divider = 0;
char which[32] = {0};
char clear_mode[32] = {0};
encoder_dev_init();
encoder_dev_set_trigmod(ENCODER_TRIG_MODE_EXTERNEL);
encoder_dev_set_divide(500, 200, 100, 500, 50);
encoder_dev_set_divide(100, 100, 100, 100, 100);
signal(SIGINT, (sig_t)sig_handler);
while (1)
{
while (strcmp(clear_mode, "i") && strcmp(clear_mode, "ei"))
{
printf("clear mode(i/ei)? ");
scanf("%s", clear_mode);
}
if (strcmp(clear_mode, "i"))
{
encoder_dev_set_clrmod(ENCODER_CLEAR_MODE_INTERNAL);
}
else
{
encoder_dev_set_clrmod(ENCODER_CLEAR_MODE_BOTH);
}
while (strcmp(which, "a") && strcmp(which, "b") && strcmp(which, "c") && strcmp(which, "d") && strcmp(which, "all"))
{
printf("which camera(a/b/c/d/all)? ");
@ -48,8 +63,9 @@ int main(int argc, char *argv[])
a = b = c = d = divider;
}
encoder_dev_set_divide(500, a, b, c, d);
printf("divider of camera %s is set to %d\r\n\r\n", which, divider);
printf("clear mode is %s, divider of camera %s is set to %d\r\n\r\n", clear_mode, which, divider);
which[0] = '\0';
clear_mode[0] = '\0';
}
}

View File

@ -1 +1 @@
1.3
1.4