智能车制作
标题:
关于野火dma库的一些问题
[打印本页]
作者:
我的奋斗
时间:
2014-5-15 12:00
标题:
关于野火dma库的一些问题
求助火哥,论坛里的各位大神,我们是K60,用的摄像头是ov7620,用羽良工作室的ov7620采集代码,用的野火的K60库,但是我们的主板上的摄像头8位数据口是PTC8到PTC15,但是羽良工作室的8位数据口用的是PTD0到PTD7,我用PTD0到PTD7能够采集成功图像,但是用PTC8到PTC15就不能采集成功。。我怀疑野火的dma库好像对8位源数据口有限制,但是我也不清楚到底哪些源数据口能用。。就是这句代码。。DMA_PORTx2BUFF_Init (DMA_CH4, (void *)&PTD_BYTE0_IN, Pix_Data, PTC0, DMA_BYTE1, H, DMA_rising_keepon);
//DMA通道4初始化,PTC0上升沿触发DMA传输,源地址为PTD_BYTE0_IN,目的地址为:Pix_Data ,每次传输1Byte,传输H次后停止传输,目的地址保持不变,关闭通道CHn 硬件请求
我把其中的PTD_BYTE0_IN换成PTC_BYTE1_IN就采集不回任何数据了,是不是除了这句代码,程序还要用修改其他的代码啊。。。。。。跪求大神。。。
作者:
野火
时间:
2014-5-15 19:15
没限制的啊,按理改成 PTC_BYTE1_IN 就可以正常采集的啊,会自动根据输入寄存器来自动初始化的。例如我们用的是 PTB_BYTE0_IN
那采集回来是什么数据?是不是有IO冲突?
作者:
我的奋斗
时间:
2014-5-15 19:34
野火 发表于 2014-5-15 19:15
没限制的啊,按理改成 PTC_BYTE1_IN 就可以正常采集的啊,会自动根据输入寄存器来自动初始化的。例如我们用 ...
IO口有冲突应该不太可能,我直接接的最小系统版单测的摄像头,我发现只要是BYTE0_IN不论哪个口都可以采集,但是如果改成BYTE1_IN 的话就只回传回来一堆0,1 的乱码,总之我野火的底层库好像对8位源数据口有限制
void DMA_PORTx2BUFF_Init(DMA_CHn CHn, void *SADDR, void *DADDR, PTxn ptxn, DMA_BYTEn byten, u32 count, DMA_PORTx2BUFF_cfg cfg)
{
u8 n, i, tmp;
ASSERT( //用断言检测 源地址和每次传输字节数是否正确
( (byten == DMA_BYTE1) //传输一个字节
&& ( (SADDR >= &PTA_BYTE0_IN) && (SADDR <= ( &PTE_BYTE3_IN )))
)
|| ( (byten == DMA_BYTE2) //传输两个字节(注意,不能跨端口)
&& ( (SADDR >= &PTA_BYTE0_IN)
&& (SADDR <= ( &PTE_WORD1_IN ))
&& (((u32)SADDR & 0x03) != 0x03) ) //保证不跨端口
)
|| ( (byten == DMA_BYTE4) //传输四个字节
&& ((SADDR >= &PTA_BYTE0_IN) && (SADDR <= ( &PTE_BYTE0_IN )))
&& (((u32)SADDR & 0x03) == 0x00) //保证不跨端口
)
);
u8 BYTEs = (byten == DMA_BYTE1 ? 1 : (byten == DMA_BYTE2 ? 2 : (byten == DMA_BYTE4 ? 4 : 16 ) ) ); //计算传输字节数
/* 开启时钟 */
SIM_SCGC7 |= SIM_SCGC7_DMA_MASK; //打开DMA模块时钟
SIM_SCGC6 |= SIM_SCGC6_DMAMUX_MASK; //打开DMA多路复用器时钟
/* 配置 DMA 通道 的 传输控制块 TCD ( Transfer Control Descriptor ) */
DMA_SADDR(CHn) = (u32)SADDR; // 设置 源地址
DMA_DADDR(CHn) = (u32)DADDR; // 设置目的地址
DMA_SOFF(CHn) = 0x00u; // 设置源地址偏移 = 0x0, 即不变
DMA_DOFF(CHn) = BYTEs; // 每次传输后,目的地址加 BYTEs
DMA_ATTR(CHn) = (0
| DMA_ATTR_SMOD(0x0) // 源地址模数禁止 Source address modulo feature is disabled
| DMA_ATTR_SSIZE(byten) // 源数据位宽 :DMA_BYTEn 。 SSIZE = 0 -> 8-bit ,SSIZE = 1 -> 16-bit ,SSIZE = 2 -> 32-bit ,SSIZE = 4 -> 16-byte
| DMA_ATTR_DMOD(0x0) // 目标地址模数禁止
| DMA_ATTR_DSIZE(byten) // 目标数据位宽 :DMA_BYTEn 。 设置参考 SSIZE
);
DMA_CITER_ELINKNO(CHn) = DMA_CITER_ELINKNO_CITER(count); //当前主循环次数
DMA_BITER_ELINKNO(CHn) = DMA_BITER_ELINKYES_BITER(count);//起始主循环次数
DMA_CR &= ~DMA_CR_EMLM_MASK; // CR[EMLM] = 0
//当CR[EMLM] = 0 时:
DMA_NBYTES_MLNO(CHn) = DMA_NBYTES_MLNO_NBYTES(BYTEs); // 通道每次传输字节数,这里设置为BYTEs个字节。注:值为0表示传输4GB */
/* 配置 DMA 传输结束后的操作 */
DMA_SLAST(CHn) = 0; //调整 源地址的附加值,主循环结束后恢复 源地址
DMA_DLAST_SGA(CHn) = (u32)( (cfg & 0x20) == 0 ? (-count) : 0 ); //调整目的地址的附加值,主循环结束后恢复目的地址或者保持地址
DMA_CSR(CHn) = (0
| DMA_CSR_DREQ_MASK //主循环结束后停止硬件请求
| DMA_CSR_INTMAJOR_MASK //主循环结束后产生中断
);
/* 配置 DMA 触发源 */
DMAMUX_CHCFG_REG(DMAMUX_BASE_PTR, CHn) = (0
| DMAMUX_CHCFG_ENBL_MASK /* Enable routing of DMA request */
//| DMAMUX_CHCFG_TRIG_MASK /* Trigger Mode: Periodic PIT周期触发传输模式 通道1对应PIT1,必须使能PIT1,且配置相应的PIT定时触发 */
| DMAMUX_CHCFG_SOURCE((ptxn >> 5) + DMA_Port_A) /* 通道触发传输源: */
);
SIM_SCGC5 |= (SIM_SCGC5_PORTA_MASK << (ptxn>>5)); //开启PORTx端口
GPIO_PDDR_REG(GPIOx[(ptxn>>5)]) &= ~(1 << (ptxn & 0x1f)); //设置端口方向为输入
PORT_PCR_REG(PORTX[(ptxn>>5)], (ptxn & 0x1F)) = ( 0
| PORT_PCR_MUX(1) // 复用GPIO
| PORT_PCR_IRQC(cfg & 0x03 ) // 确定触发模式
| ((cfg & 0xc0 ) >> 6) // 开启上拉或下拉电阻,或者没有
);
GPIO_PDDR_REG(GPIOx[(ptxn>>5)]) &= ~(1 << (ptxn && 0x1F)); //输入模式
/* 配置输入源 */
SIM_SCGC5 |= (SIM_SCGC5_PORTA_MASK << ((((u32)SADDR) & 0x1ff)>>6)); //开启PORTx端口
switch(byten)
{
case DMA_BYTE1:
*((u8 *)((u32)SADDR + 4)) = 0; //设置为输入方向。为什么加4?PDIR地址加4后,就变成对应的PDDR地址
break;
case DMA_BYTE2:
*((u16 *)((u32)SADDR + 4)) = 0;
break;
case DMA_BYTE4:
*((u32 *)((u32)SADDR + 4)) = 0;
break;
default:
assert_failed(__FILE__, __LINE__);
break;
}
/* 输入源管脚选择功能脚 */
n = (u8)(((u32)SADDR - ((u32)(&PTA_BYTE0_IN))) & 0x3f); //最小的引脚号
tmp = n + (BYTEs << 3); //最大的引脚号
for(i = n; i < tmp; i++)
{
PORT_PCR_REG(PORTX[ ((((u32)SADDR)&0x1ff)>>6) ], i) = (0
| PORT_PCR_MUX(1)
| GPI_DOWN //输入源应该下拉,默认读取到的是0
);
}
/* 开启中断 */
//DMA_EN(CHn); //使能通道CHn 硬件请求
DMA_IRQ_EN(CHn); //允许DMA通道传输//晓克注:允许DMA通道CHn产生中断,一次采集结束触发中断
}
就是这段初始化代码
作者:
我的奋斗
时间:
2014-5-15 19:38
我多做了几次尝试,只要是BYTE0_IN 不论哪组口都能用,但是只要换成BYTE1_IN 就没有一组行的。。。。void DMA_PORTx2BUFF_Init(DMA_CHn CHn, void *SADDR, void *DADDR, PTxn ptxn, DMA_BYTEn byten, u32 count, DMA_PORTx2BUFF_cfg cfg)
{
u8 n, i, tmp;
ASSERT( //用断言检测 源地址和每次传输字节数是否正确
( (byten == DMA_BYTE1) //传输一个字节
&& ( (SADDR >= &PTA_BYTE0_IN) && (SADDR <= ( &PTE_BYTE3_IN )))
)
|| ( (byten == DMA_BYTE2) //传输两个字节(注意,不能跨端口)
&& ( (SADDR >= &PTA_BYTE0_IN)
&& (SADDR <= ( &PTE_WORD1_IN ))
&& (((u32)SADDR & 0x03) != 0x03) ) //保证不跨端口
)
|| ( (byten == DMA_BYTE4) //传输四个字节
&& ((SADDR >= &PTA_BYTE0_IN) && (SADDR <= ( &PTE_BYTE0_IN )))
&& (((u32)SADDR & 0x03) == 0x00) //保证不跨端口
)
);
u8 BYTEs = (byten == DMA_BYTE1 ? 1 : (byten == DMA_BYTE2 ? 2 : (byten == DMA_BYTE4 ? 4 : 16 ) ) ); //计算传输字节数
/* 开启时钟 */
SIM_SCGC7 |= SIM_SCGC7_DMA_MASK; //打开DMA模块时钟
SIM_SCGC6 |= SIM_SCGC6_DMAMUX_MASK; //打开DMA多路复用器时钟
/* 配置 DMA 通道 的 传输控制块 TCD ( Transfer Control Descriptor ) */
DMA_SADDR(CHn) = (u32)SADDR; // 设置 源地址
DMA_DADDR(CHn) = (u32)DADDR; // 设置目的地址
DMA_SOFF(CHn) = 0x00u; // 设置源地址偏移 = 0x0, 即不变
DMA_DOFF(CHn) = BYTEs; // 每次传输后,目的地址加 BYTEs
DMA_ATTR(CHn) = (0
| DMA_ATTR_SMOD(0x0) // 源地址模数禁止 Source address modulo feature is disabled
| DMA_ATTR_SSIZE(byten) // 源数据位宽 :DMA_BYTEn 。 SSIZE = 0 -> 8-bit ,SSIZE = 1 -> 16-bit ,SSIZE = 2 -> 32-bit ,SSIZE = 4 -> 16-byte
| DMA_ATTR_DMOD(0x0) // 目标地址模数禁止
| DMA_ATTR_DSIZE(byten) // 目标数据位宽 :DMA_BYTEn 。 设置参考 SSIZE
);
DMA_CITER_ELINKNO(CHn) = DMA_CITER_ELINKNO_CITER(count); //当前主循环次数
DMA_BITER_ELINKNO(CHn) = DMA_BITER_ELINKYES_BITER(count);//起始主循环次数
DMA_CR &= ~DMA_CR_EMLM_MASK; // CR[EMLM] = 0
//当CR[EMLM] = 0 时:
DMA_NBYTES_MLNO(CHn) = DMA_NBYTES_MLNO_NBYTES(BYTEs); // 通道每次传输字节数,这里设置为BYTEs个字节。注:值为0表示传输4GB */
/* 配置 DMA 传输结束后的操作 */
DMA_SLAST(CHn) = 0; //调整 源地址的附加值,主循环结束后恢复 源地址
DMA_DLAST_SGA(CHn) = (u32)( (cfg & 0x20) == 0 ? (-count) : 0 ); //调整目的地址的附加值,主循环结束后恢复目的地址或者保持地址
DMA_CSR(CHn) = (0
| DMA_CSR_DREQ_MASK //主循环结束后停止硬件请求
| DMA_CSR_INTMAJOR_MASK //主循环结束后产生中断
);
/* 配置 DMA 触发源 */
DMAMUX_CHCFG_REG(DMAMUX_BASE_PTR, CHn) = (0
| DMAMUX_CHCFG_ENBL_MASK /* Enable routing of DMA request */
//| DMAMUX_CHCFG_TRIG_MASK /* Trigger Mode: Periodic PIT周期触发传输模式 通道1对应PIT1,必须使能PIT1,且配置相应的PIT定时触发 */
| DMAMUX_CHCFG_SOURCE((ptxn >> 5) + DMA_Port_A) /* 通道触发传输源: */
);
SIM_SCGC5 |= (SIM_SCGC5_PORTA_MASK << (ptxn>>5)); //开启PORTx端口
GPIO_PDDR_REG(GPIOx[(ptxn>>5)]) &= ~(1 << (ptxn & 0x1f)); //设置端口方向为输入
PORT_PCR_REG(PORTX[(ptxn>>5)], (ptxn & 0x1F)) = ( 0
| PORT_PCR_MUX(1) // 复用GPIO
| PORT_PCR_IRQC(cfg & 0x03 ) // 确定触发模式
| ((cfg & 0xc0 ) >> 6) // 开启上拉或下拉电阻,或者没有
);
GPIO_PDDR_REG(GPIOx[(ptxn>>5)]) &= ~(1 << (ptxn && 0x1F)); //输入模式
/* 配置输入源 */
SIM_SCGC5 |= (SIM_SCGC5_PORTA_MASK << ((((u32)SADDR) & 0x1ff)>>6)); //开启PORTx端口
switch(byten)
{
case DMA_BYTE1:
*((u8 *)((u32)SADDR + 4)) = 0; //设置为输入方向。为什么加4?PDIR地址加4后,就变成对应的PDDR地址
break;
case DMA_BYTE2:
*((u16 *)((u32)SADDR + 4)) = 0;
break;
case DMA_BYTE4:
*((u32 *)((u32)SADDR + 4)) = 0;
break;
default:
assert_failed(__FILE__, __LINE__);
break;
}
/* 输入源管脚选择功能脚 */
n = (u8)(((u32)SADDR - ((u32)(&PTA_BYTE0_IN))) & 0x3f); //最小的引脚号
tmp = n + (BYTEs << 3); //最大的引脚号
for(i = n; i < tmp; i++)
{
PORT_PCR_REG(PORTX[ ((((u32)SADDR)&0x1ff)>>6) ], i) = (0
| PORT_PCR_MUX(1)
| GPI_DOWN //输入源应该下拉,默认读取到的是0
);
}
/* 开启中断 */
//DMA_EN(CHn); //使能通道CHn 硬件请求
DMA_IRQ_EN(CHn); //允许DMA通道传输//晓克注:允许DMA通道CHn产生中断,一次采集结束触发中断
}
就是这个初始化代码,是不是有问题?
作者:
我的奋斗
时间:
2014-5-15 19:47
我用的是野火比较老版本的库
作者:
zhao1992629
时间:
2014-5-15 20:26
在野火的基础上将dma其他功能整理成库
作者:
breaker_d
时间:
2014-7-5 09:56
野火 发表于 2014-5-15 19:15
没限制的啊,按理改成 PTC_BYTE1_IN 就可以正常采集的啊,会自动根据输入寄存器来自动初始化的。例如我们用 ...
*** 我们板子上摄像头数据口对应的是C10-C17 怎么破?
作者:
wustyhj
时间:
2015-1-23 11:37
野火 发表于 2014-5-15 19:15
没限制的啊,按理改成 PTC_BYTE1_IN 就可以正常采集的啊,会自动根据输入寄存器来自动初始化的。例如我们用 ...
野火大哥你好,我有个问题就是,DMA摄像头采集那边 ,每一次目的地址加一 然后主循环就是列数,那么一列进行完之后目的地址又变为0,那么怎么调到第二行,我不懂代码里面哪一句是,我现在遇到的问题就是 只能采到第一行的数据,
欢迎光临 智能车制作 (http://dns.znczz.com/)
Powered by Discuz! X3.2