基于STM32的PCL6045B开发体会
于是公司从每个不同项目组抽选人员组成了一个团队。本人负责软件部分,负责编写驱动程序和调试电路板。
全新项目,有一定挑战性。经过分析,决定采用STM32总线方式(FSMC)驱动PCL6045B。对比FSMC的四种总线操作时序和PCL6045B操作时序。认为应该选用STM32的PCCARD模式操作。从数据库中查找了一些文献资料,就开干起来了。
两名硬件工程师按我的需求设计好硬件电路板。
接下来分成以下几个步骤进行:
首先就是建立通讯。让ARM能跟PCL6045B建立起来通讯。
这一步主要就是配置STM32的FSMC为PCCARD模式,配置的过程就是按官方手册上配置的。先系统初始化配置好STM32的时钟(不赘述)。然后就是初始化端口,这里需要注意的是,要将跟FSMC相关的端口都设置为特殊功能口AF。如下:
void PCCARD_IO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD RCC_APB2Periph_GPIOE RCC_APB2Periph_GPIOF RCC_APB2Periph_GPIOG,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 GPIO_Pin_2 GPIO_Pin_3 GPIO_Pin_4 GPIO_Pin_12 GPIO_Pin_5;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOF, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 GPIO_Pin_8 GPIO_Pin_9 GPIO_Pin_10 GPIO_Pin_11 GPIO_Pin_12 GPIO_Pin_13 GPIO_Pin_14 GPIO_Pin_15;
GPIO_Init(GPIOE, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14 GPIO_Pin_15 GPIO_Pin_10 GPIO_Pin_9 GPIO_Pin_8 GPIO_Pin_1 GPIO_Pin_0;
GPIO_Init(GPIOD, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 GPIO_Pin_5;//NOE,NWE引脚
GPIO_Init(GPIOD, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//cs
GPIO_Init(GPIOG, &GPIO_InitStructure);
}
接下来就是配置FSMC PC卡模式时序。如下:
void PCCARD_Init(void)
{
FSMC_PCCARDInitTypeDef FSMC_PCCARDInitStructure;
FSMC_NAND_PCCARDTimingInitTypeDef p;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC, ENABLE);////
p.FSMC_SetupTime = 0x02;
p.FSMC_WaitSetupTime = 0x04;
p.FSMC_HoldSetupTime = 0x02;
p.FSMC_HiZSetupTime = 0x03;
FSMC_PCCARDInitStructure.FSMC_Waitfeature = FSMC_Waitfeature_Enable ; //使能等待
FSMC_PCCARDInitStructure.FSMC_TCLRSetupTime = 0x10;
FSMC_PCCARDInitStructure.FSMC_TARSetupTime = 0x10;
FSMC_PCCARDInitStructure.FSMC_CommonSpaceTimingStruct = &p;
FSMC_PCCARDInitStructure.FSMC_AttributeSpaceTimingStruct = &p;
FSMC_PCCARDInitStructure.FSMC_IOSpaceTimingStruct = &p;
FSMC_PCCARDInit(&FSMC_PCCARDInitStructure);
FSMC_PCCARDCmd(ENABLE);
}
到这里,就算配置完成。主函数调用。
然后主函数通过控制PCL6045的其中一个口实验成功,于是就算建立起了通信。
接下来就可以试验控制PCL6045参数指定数目的脉冲了。
于是,我根据手册又编写了如下小测试程序:
p645_wreg(AXS_AU, WPRMD, 0x00000041); //定长运动模式
p645_wreg(AXS_AU, WRMV, 4012000000);
p645_wreg(AXS_AU, WRFL, 500L);
p645_wreg(AXS_AU, WRFH, 20000L);
p645_wreg(AXS_AU, WRUR, 200L);
p645_wreg(AXS_AU, WRDR, 400L);
p645_wreg(AXS_AU, WRMG, 29L);
p645_wcom(AXS_AU,STAUD);
运行,成功产生脉冲!
正常过程很简单,但是,实际操作中,特别是第一次摸索的时候,遇到很多棘手的问题。
比如PCL6045 硬件部分IF0 IF1 要接成8086方式。
一开始,我们的硬件电路按如下图链接:
好像也没什么问题,于是就接着往下调,发现了一个很郁闷的问题,当时把问题描述如下:
#define AXS_AX ((volatile unsigned int ) 0x90000000)
#define AXS_AY ((volatile unsigned int ) 0x90000004)
#define AXS_AZ ((volatile unsigned int ) 0x9000008)
#define AXS_AU ((volatile unsigned int ) 0x900000c)
其中 AXS_AX、AXS_AY、AXS_AZ、AXS_AU 分别表示 X、Y、Z、U 轴寄存器的起始地址
几个地址均已经能够操作,能控制各个轴电机运动。
STM32通过FSMC与DSP通讯,通过16位传送数据。
#define outpw( address,data) (*(unsigned short *)(address)=(data));
unsigned int inpw(unsigned int address) //读写某一段内存
{
unsigned short data;
data=*(unsigned short*)address;
return data;
}
写寄存器函数如下:
void p645_wreg(unsigned int base_addr,unsigned int rwcom,unsigned int data) //向某个轴的某个寄存器写入数据
{
union udata{
unsigned int ldata;
unsigned short idata[2];
}udt;
udt.ldata = data;
outpw (base_addr 2, udt. idata[0]);
// Delay_Us(1); //就算加了延时也无效
outpw (base_addr 3, udt. idata[1]);
// Delay_Us(1); //就算加了延时也无效
outpw (base_addr, rwcom);
}
//读寄存器函数如下:
unsigned long p645_rreg (unsigned int base_addr,unsigned int rrcom) //读寄存器
{
unionudata{
unsigned int ldata;
unsigned short idata[2];
}udt;
outpw(base_addr, rrcom);
// Delay_Us(1);
udt.idata[0] = inpw (base_addr 2);
// Delay_Us(1);
udt.idata[1] = inpw (base_addr 3);
return(udt. ldata);
}
在设置解码倍频时,发现,无论我写入的是哪个数(00,01,10),都不能改变编码器读出的数据,即始终是默认的1倍解码,即相关寄存器两个bit是00的情况.
于是我猜想是不是我写入的数据不能改变高16位,只能改变低16位.
所以我就做了以下测试工作:
现在发现向DSP各轴缓冲区写入数据时,总是不能写进去高16位,而低十六位能写进去。比如,我写p645_wreg(AXS_AX,WRENV1,0x00000001); //控制脉冲类型。
p645_wreg(AXS_AX,WRENV1,0x00000002);
p645_wreg(AXS_AX,WRENV1,0x00000003);
分别能看到输出不同类型的脉冲。证明低位操作有效!
但是当我写做定长测试时,代码如下
p645_wreg(AXS_AZ, WPRMD, 0x00000041); //定长运动模式
p645_wreg(AXS_AZ, WRMV, 65536L);//这里写入65535以下的数均能准确控制电机走的步数,超过65535,则会出现电机持续运动而不受控制的异常状况!
p645_wreg(AXS_AZ, WRFL, 500L);
p645_wreg(AXS_AZ, WRFH, 2000L);
p645_wreg(AXS_AZ, WRUR, 200L);
p645_wreg(AXS_AZ, WRDR, 400L);
p645_wreg(AXS_AZ, WRMG, 5L);
p645_wcom(AXS_AZ,STAUD);
另外,超过65535时我读取出COUNT1中数据也是没有规律的。而不超过65535时,则完全正常!
1.当写入65535时,电机运转过程读出数据如下:
Counter1 Counter2
指令 编码器(这里是默认的1倍,跟我们的编码器对应上是对的)
0000019662 0000000958
0000039790 0000001937
0000059918 0000002917
0000065535 0000003191
0000065535 0000003191
0000065535 0000003191
0000065535 0000003191
2.当写入65536及以上时,电机运转过程读出数据如下:
Counter1 Counter2
指令编码器(这里是默认的1倍,跟我们的编码器对应上是对的)
0000019662 0000000958
0000039790 0000001937
0000059917 0000002917
0000014509 0000003898
0000034637 0000004878
0000054764 0000005857
0000009356 0000006837
0000029484 0000007818
0000049611 0000008797
0000004203 0000009776
0000044458 0000011737
0000064586 0000012718
0000019177 0000013697
0000039305 0000014676
0000059433 0000015657
0000034152 0000017617
0000054279 0000018596
0000008871 0000019577
0000028999 0000020557
0000049126 0000021536
0000003718 0000022516
0000023846 0000023497
0000043973 0000024476
0000018692 0000026436
0000058948 0000028397
0000013539 0000029375
0000033667 0000030355
0000053794 0000031335
以上数据均不超过65535
基于上述现象,我做了个程序来测试 读写,发现,我写入的数据到缓冲去时超过0x00ffffff时,读出来的数据是不对的,只有低24位能读出来,高8位读出来的均是0.
写寄存器函数修改如下:
void p645_wreg(unsigned int base_addr,unsigned int rwcom,unsigned intdata)
{
unionudata{
unsigned int ldata;
unsigned short idata[2];
}udt;
udt.ldata = data;
outpw (base_addr 2, udt. idata[0]);
outpw (base_addr 3, udt. idata[1]);
//outpw (base_addr, rwcom);
}
测试代码如下:
p645_wreg(AXS_AZ,WRENV2,0xffffffff);
data3=inpw (AXS_AZ 2);
data4=inpw (AXS_AZ 3);
读出的数据只能是data3=65535;data4=255,即最高8位丢失!
当p645_wreg(,,); 写入的数据是低0x00ffffff以下的数据时,data3;data4读出来的数据是对的。即写什么读出什么。这就是对我现在遇到的问题的详细叙述。
STM32PCL6045B开发体 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)