打印
[工具和软件]

从零入手Kinetis系统开发之FlexBus模块

[复制链接]
2211|33
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主

FlexBus应用, 在上一系列就已经预报了,结果拖到现在,让一些等着的博友等了这么久,惭愧惭愧,以后应承下来的就尽量早点搞完,越拖越写不动,真的体会到这种感觉。其实前一周一边在准备众星捧月的比赛,一边在写Kinetis的USB底层驱动,一直到前天才开始准备写该篇了,本来是想着趁热打铁的把USB模块介绍出来的,不过还是决定先把这篇补上再说,后续篇章会写出来Kinetis的USB模块(由于USB内容较庞大,我整整搞了一周,所以打算分成几篇写出来,有用到的敬请期待,呵呵,这次不会太久),希望不会让大家失望才好,哈哈。

    FlexBus模块,我早在今年年前就写好了并作为开发框架代码的一部分一块上传到了飞思卡尔创意嘉年华小组里了,后来又写了篇FlexBus外扩SRAM的硬件篇,本来作为核心的软件篇早就该写出来了,结果难产到现在,呵呵,有些东西都忘记了,所以又花费了两天时间熟悉了下,又发现了一些包括软件和硬件上的小Bug,总算今天让它新鲜出炉了,enjoy it... ...好了,说了这么多,下面进入正题了:

    FlexBus,以前有博友问过我是什么bus,呵呵,其实就是飞思卡尔自己的一种外部总线接口,可以用来扩展诸如外部ROM、SRAM、可编程逻辑器件或者一些从设备之类的,很灵活方便。我个人觉着感觉挺好用的,自己也实际应用了,扩展了一片ISSI的SRAM,用起来还是比较爽的,不过最开始我的硬件设计上有点问题(建议看本篇的时候结合我写的关于FlexBus的硬件篇《说说K60的FlexBus外扩SRAM接口》,有些东西上篇提了我这里就不重点说了),现在给出改进后的硬件反相电路,以前的FB_AD0的频率达到500k bps以上的时候,FB_AD0_B就会跟不上,波形严重失真,严重的时候三极管不能关断,结果造成反相失败,经过如下改进之后加了一个加速电容,减小集电极电阻,又在基极加了泄流电阻,提高了三极管开关导通速率(这些是硬件设计的一些经验,这里需要提一下,咱们这些搞嵌入式开发的,不能老是盯着单片机软件编程这一块,硬件设计很重要,有时候硬件上的一点点改进有可能会提高你的工程质量一个档次),经过测试FB_AD0达到1M以上还是可以正常工作的,不过如果条件允许的话还是建议用非门反相吧,我当初是为了节省板子面积才折衷了三极管的方式,结果造成了很大的困扰,现在在FlexBusClock 20M以下还可以正常使用,再往上就不敢保证了。

以上是对《说说K60的FlexBus外扩SRAM接口》的那篇博客的补充和更正,呵呵,如果上篇已经熟悉了,就直接跳到该段软件编程部分即可,软件编程部分,感觉还是比较简单的,思路较清晰,需要操作的寄存器较少,只要在初始化阶段设置好几个寄存器就可以任意操作FlexBus总线了,呵呵,下面就着重说说软件编程需要的几个寄存器了:

(1)FB_CSARn,即片选地址寄存器:

该寄存器即配置相应的外部片选信号FB_CSn的地址范围的(即基地址),即设定BA段为某个基地址,当MCU寻址范围处在该基地址范围的时候,相应的FB_CSn为低电平,选中相应的外设,从而进行进一步的读写操作。当然这里需要着重强调一下,这个基地址范围不是我们随意设置的,由Kinetis的内存映射可以看出来,该基地址只在该范围下有效(以前有过博友问过我这个问题,这个地址不能随便设置的),如下:

(2)FB_CSMRn,我姑且叫它片选基地址屏蔽寄存器:

之所以叫它基地址屏蔽寄存器主要是BAM字段的作用了,由FB_CSAR寄存器可知,它只受32位总线地址的高16位影响,如果设置FB_CSARn=0x6000_0000,那么在寻址范围在0x6000_0000~0x6000_FFFF的范围内都是有效的(即FB_CSn有效),即FlexBus的最小寻址地址块为2^16=64KB大小,而如果你想要在该基地址范围下寻址更大的范围,嘿嘿,那就要用到BAM字段了,其作用我觉着用英语表达更容易理解,即 Setting a BAM bit causes the corresponding CSAR bit to be a don’t care in the decode,直接这么说估计好些人不明白,那我就用例子说明一下,设置FB_CSAR[BA]=0x6000,FB_CSMR[BAM]=0x0001,则相应的FB_CS的片选范围为0x6000_0000~0x6000_FFFF和0x6001_0000~0x6001_FFFF连续的128KB的空间,即BAM相应位的作用就是屏蔽了BA相应位在寻址译码上的作用。说完这个再说下地址连续性的概念,同样设置FB_CSAR[BA]=0x6000,而FB_CSMR[BAM]=0x0004的话,则相应的FB_CS的片选范围则是0x6000_0000~0x6000_FFFF和0x6004_0000~0x6004_FFFF这两个不连续的128KB的空间,而如果设置FB_CSMR[BAM]=0x0007的话,则寻址范围则为0x6000_0000~0x6007_FFFF这连续512KB的空间,呵呵,这个寄存器作用理解起来有点难,所以说了这么多,还没明白的还是继续啃英文datasheet吧。

最后要说说FB_CSMR[V]这个位段,即片选有效信号,这里值得一提的是,MCU复位之后只有FB_CS0有效,如果需要用到其他的片选信号,则必须先置位FB_CSMR0[V](注意是CSMR0),然后才能使用其他片选信号。

(3)FB_CSCRn,即片选控制寄存器:

该寄存器也很重要,涉及到数据端口位数,对齐方式等等,这里就挑我们接下来的软件编程需要的说说。FB_CSCR[PS],即数据端口大小,跟FB_CSCR[BLS](对齐方式)配合,决定FlexBus数据总线的端口的分配和大小,我由于采用了8位端口(见我的FlexBus的硬件电路设计篇)所以进行了相应的设计。

(4)FB_CSPMCR,即FlexBus的引脚复用功能控制寄存器

这个寄存器涉及到一些复用的选择,根据个人实际应用来配置,所以具体内容还是根据datasheet来设置吧,这里就这么一提,琢磨深入的话还是钻进E文研究一番吧,哈哈~

    主要的寄存器都介绍完了,其实还有IO管脚的复用寄存器,不过独属于FlexBus模块,而且在以前的应用中也都用过,这里就不提了,下面废话不多说了,呵呵,直接上代码了,主要是两个函数接口——FlexBus的初始化函数和管脚复用选择函数(具体操作我都已经注释了,有中文有E文的,至于为什么老用E文注释,是因为觉着有的时候用E文注释看起来更明白些,不知道有同感没,嘿嘿):

/*****************************************************************************************
** Routine: FlexBus_Init(to understand the workfolw, refer to datasheet page714)
** Description: initialize the FlexBus for extern SRAM
                FB_CS       --- chip select(Chip_S0, Chip_S1, Chip_S2, Chip_S3, Chip_S4, Chip_S5)
                BASE_ADDRESS--- the base address for the corresponding chip select
                Port_Size   --- data port size(BIT_8, BIT_16, BIT_32)
                Block_Size  --- Block_64KB, Block_128KB, Block_256KB, Block_512KB, Block_1MB
*****************************************************************************************/
void FlexBus_Init(uint8 FB_CS, vuint16* BASE_ADDRESS, uint8 Port_Size, uint8 Block_Size)
{
  // Chip select address resgister
  FB_CSAR_REG(FB_BASE_PTR,FB_CS) = (uint32) BASE_ADDRESS;   /* Set base address. */
  // Chip select control register
  FB_CSCR_REG(FB_BASE_PTR,FB_CS) =
                    FB_CSCR_PS(Port_Size)  /* Set port size */
                    | FB_CSCR_AA_MASK
                    | FB_CSCR_ASET(0x1)
//                  | FB_CSCR_BLS_MASK     /* Data is right justified on FB_AD, FB_AD[15:0] */
                    | FB_CSCR_WS(0x1) ;  
  // Chip select mask register
  /*
    * Note: At reset, no chip-select other than FB_CS0 can be used until
    * the CSMR0[V] is set. Afterward, FB_CS[5:0] functions as programmed.
  */
/* Set base address mask for corresponding address space */
  FB_CSMR_REG(FB_BASE_PTR,FB_CS) =
                    FB_CSMR_BAM(Block_Size)
                    | FB_CSMR_V_MASK   ;        /* Enable cs signal */                              
}

相关帖子

沙发
我思故我在12345|  楼主 | 2015-4-23 21:23 | 只看该作者
下面的函数我根据我的实际板子设计做了些更改,跟我当初上传的不太一样,注意下......
/*****************************************************************************************
** Routine: FlexBus_Pins_Multiplex
** Description: configure the pin muliplexing function according to the above seting
                (FlexBus_Init).
                Default setting: 20MHz FlexBus clock(Be setted in mcg);
                                 2M*8bits space address
                                 4 chip select signals(cs0, cs1, cs2, cs3)
*****************************************************************************************/
void FlexBus_Pins_Multiplex(void)
{
  // Chip select port multiplexing control register
  FB_CSPMCR = FB_CSPMCR_GROUP1(1)      /* FB_CS1 */
             | FB_CSPMCR_GROUP2(0)     /* FB_CS4 */
             | FB_CSPMCR_GROUP3(0)     /* FB_CS5 */
             | FB_CSPMCR_GROUP4(1)     /* FB_CS2 */
             | FB_CSPMCR_GROUP5(1)     /* FB_CS3 */
             ;
  //SIM_CLKDIV1 |= SIM_CLKDIV1_OUTDIV3(0x3);    /* Has been setted in mcg.c file */
  /*
   * Configure the pins needed to FlexBus Function (Alt 5)
   * this example uses low drive strength settings         
  */
  //address
  PORTB_PCR9  = PORT_PCR_MUX(5);           //  fb_ad[20]
  PORTB_PCR10 = PORT_PCR_MUX(5);          //  fb_ad[19]  
  PORTB_PCR11 = PORT_PCR_MUX(5);          //  fb_ad[18]
  PORTB_PCR16 = PORT_PCR_MUX(5);          //  fb_ad[17]
  PORTB_PCR17 = PORT_PCR_MUX(5);          //  fb_ad[16]
  PORTB_PCR18 = PORT_PCR_MUX(5);          //  fb_ad[15]
  PORTC_PCR0  = PORT_PCR_MUX(5);           //  fb_ad[14]
  PORTC_PCR1  = PORT_PCR_MUX(5);           //  fb_ad[13]
  PORTC_PCR2  = PORT_PCR_MUX(5);           //  fb_ad[12]
  PORTC_PCR4  = PORT_PCR_MUX(5);           //  fb_ad[11]
  PORTC_PCR5  = PORT_PCR_MUX(5);           //  fb_ad[10]
  PORTC_PCR6  = PORT_PCR_MUX(5);           //  fb_ad[9]
  PORTC_PCR7  = PORT_PCR_MUX(5);           //  fb_ad[8]
  PORTC_PCR8  = PORT_PCR_MUX(5);           //  fb_ad[7]
  PORTC_PCR9  = PORT_PCR_MUX(5);           //  fb_ad[6]
  PORTC_PCR10 = PORT_PCR_MUX(5);          //  fb_ad[5]
  PORTD_PCR2  = PORT_PCR_MUX(5);           //  fb_ad[4]
  PORTD_PCR3  = PORT_PCR_MUX(5);           //  fb_ad[3]
  PORTD_PCR4  = PORT_PCR_MUX(5);           //  fb_ad[2]
  PORTD_PCR5  = PORT_PCR_MUX(5);           //  fb_ad[1]
  PORTD_PCR6  = PORT_PCR_MUX(5);           //  fb_ad[0]
  //data
  PORTB_PCR20 = PORT_PCR_MUX(5);           //  fb_ad[31] used as d[7]
  PORTB_PCR21 = PORT_PCR_MUX(5);           //  fb_ad[30] used as d[6]
  PORTB_PCR22 = PORT_PCR_MUX(5);           //  fb_ad[29] used as d[5]
  PORTB_PCR23 = PORT_PCR_MUX(5);           //  fb_ad[28] used as d[4]
  PORTC_PCR12 = PORT_PCR_MUX(5);           //  fb_ad[27] used as d[3]
  PORTC_PCR13 = PORT_PCR_MUX(5);           //  fb_ad[26] used as d[2]
  PORTC_PCR14 = PORT_PCR_MUX(5);           //  fb_ad[25] used as d[1]
  PORTC_PCR15 = PORT_PCR_MUX(5);           //  fb_ad[24] used as d[0]
  // Default control signals(base on numbers of your peripheral devices or functions)
  PORTB_PCR19 = PORT_PCR_MUX(5);           // fb_oe_b
  PORTC_PCR11 = PORT_PCR_MUX(5);           // fb_rw_b  
  PORTD_PCR1  = PORT_PCR_MUX(5);            // fb_cs0_b
  PORTD_PCR0  = PORT_PCR_MUX(5);            // fb_cs1_b
  PORTC_PCR18 = PORT_PCR_MUX(5);           // fb_cs2_b
  PORTC_PCR19 = PORT_PCR_MUX(5);           // fb_cs3_b  
}
函数接口写好了,下面就需要在app函数里调用了,我这里改写了个测试程序(由官方例程改变而成,如有巧合,实属必然,哈哈),最后是运行之后的效果,可以明显的看到,写进去的数据与读出的数据相符合,测试成功,呵呵,其实有条件的可以看看FB_CSn等几个重要操作信号的波形,那样更直观些,嘿嘿~
/****************************************************************************************************
vuint8 wdata8 = 0x00;
vuint8 rdata8 = 0x00;
vuint16 wdata16 = 0x00;
vuint16 rdata16 = 0x00;
vuint32 wdata32 = 0x00;
vuint32 rdata32 = 0x00;
void main(void)
{
  //---------------insert your code in the following
  uint16 n;
  FlexBus_Init(Chip_S0,&K60_SRAM_START_ADDRESS,BIT_8,Block_1MB);
  FlexBus_Pins_Multiplex();
  EnableInterrupts;
  while(1)
  {
    asm("nop");
    asm("nop");
    asm("nop");
    asm("nop");
    /* write 8bit data to sram */
    wdata8=0xA5;                                    //data to write to mram
    *(vuint8*)&K60_SRAM_START_ADDRESS = wdata8;          //write
    //rdata8=0x00;                                    //clear data variable;
    rdata8=(*(vuint8*)&K60_SRAM_START_ADDRESS);           //read
    /* write 16bit data to sram */
    wdata16=0x1234;                             //data to write to mram
    *(vuint16*)(&K60_SRAM_START_ADDRESS) = wdata16;   //write
   // rdata16=0x00;                                  //clear data variable;
    rdata16=(*(vuint16*)(&K60_SRAM_START_ADDRESS));    //read
    /* write 32bit data to sram */
    wdata32=0x87654321;                    //data to write to mram
    *(vuint32*)(&K60_SRAM_START_ADDRESS) = wdata32;   //write
   //rdata32=0x00;                                   //clear data variable;
    rdata32=(*(vuint32*)(&K60_SRAM_START_ADDRESS));    //read
  }
}

使用特权

评论回复
板凳
我思故我在12345|  楼主 | 2015-4-23 21:23 | 只看该作者
附件为完整的FlexBus的底层驱动软件包。
5300513837001.rar (2.16 KB)

使用特权

评论回复
地板
后会无期1| | 2015-4-23 21:24 | 只看该作者
  我想用32 bit (port size),如何用16-Byte实现32bit的burst?

使用特权

评论回复
5
我思故我在12345|  楼主 | 2015-4-23 21:25 | 只看该作者
后会无期1 发表于 2015-4-23 21:24
我想用32 bit (port size),如何用16-Byte实现32bit的burst?

不太明白你后半句的意思。不过如果你用32bit的port size的话就肯定得需要复用数据和地址了,这样的话你需要使能FB_ALE控制外部地址锁存器了~

使用特权

评论回复
6
后会无期1| | 2015-4-23 21:25 | 只看该作者
我思故我在12345 发表于 2015-4-23 21:25
不太明白你后半句的意思。不过如果你用32bit的port size的话就肯定得需要复用数据和地址了,这样的话你需 ...

是这样的,我初步是想将数据直接传送给FPGA的,所以希望FB总线只要传送数据就好,但是看了datasheet之后觉得不太可能,因为FB好像始终都要输出地址数据的,对吧?
      port size PS[1:0]      Transfer Size FB_TSIZ[1:0]         Burst-Inhibited:Number of Transfers
                                                                                                    Burst-Enabled :Number of Beats
    1*(16-bit)                         11(16bytes)                                 8
     00(32-bit)                        11(line)                                        4
另外,我说的  “我想用32 bit (port size),如何用16-Byte实现32bit的burst?”就是上边最后一行的意思。
就是送一个16bytes的数据到数据端口(32bit),模块会自动分成4beat传送,每beat 32bit。这样传输数据效率会高一点。
不知道你有明白我的意思,呵呵.

使用特权

评论回复
7
我思故我在12345|  楼主 | 2015-4-23 21:25 | 只看该作者
后会无期1 发表于 2015-4-23 21:25
是这样的,我初步是想将数据直接传送给FPGA的,所以希望FB总线只要传送数据就好,但是看了datasheet之后 ...

嗯,我理解了,不过这种方式我还没用到,不敢说,怕误导了你,呵呵。。。不过你最开始的那种设想我觉着用FPGA的话是可以实现,你可以在FPGA的RAM之前用内部逻辑资源实现一个地址锁存器,然后就可以直接用32位端口了。

使用特权

评论回复
8
后会无期1| | 2015-4-23 21:26 | 只看该作者
我思故我在12345 发表于 2015-4-23 21:25
嗯,我理解了,不过这种方式我还没用到,不敢说,怕误导了你,呵呵。。。不过你最开始的那种设想我觉着用 ...

呵呵!非常感谢!

使用特权

评论回复
9
后会无期1| | 2015-4-23 21:26 | 只看该作者
同样设置FB_CSAR[BA]=0x6000,而FB_CSMR[BAM]=0x0004的话,则相应的FB_CS的片选范围则是0x6000_0000~0x6000_FFFF和0x6004_0000~0x6004_FFFF这两个不连续的128KB的空间,而如果设置FB_CSMR[BAM]=0x0007的话,则寻址范围则为0x6000_0000~0x6007_FFFF这连续512KB的空间
//这个不是很懂,后半句是只设置FB_CSMR[BAM]=0x0007的么?

使用特权

评论回复
10
我思故我在12345|  楼主 | 2015-4-23 21:26 | 只看该作者
后会无期1 发表于 2015-4-23 21:26
同样设置FB_CSAR=0x6000,而FB_CSMR=0x0004的话,则相应的FB_CS的片选范围则是0x6000_0000~0x6000_FFFF和0x ...

嗯,这句的确很难理解,0x0007的话就表示0x0000~0x0007这个8个连续的64KB空间都可以寻址,这个你需要仔细理解手册上的英文解释~

使用特权

评论回复
11
fhguo1990| | 2015-4-23 21:27 | 只看该作者
我想问一下最后那个图中的Location的数值是怎么来的?也没看到你给K60_SRAM_START_ADDRESS赋值,不太明白,谢谢!

使用特权

评论回复
12
我思故我在12345|  楼主 | 2015-4-23 21:28 | 只看该作者
fhguo1990 发表于 2015-4-23 21:27
我想问一下最后那个图中的Location的数值是怎么来的?也没看到你给K60_SRAM_START_ADDRESS赋值,不太明白, ...

K60_SRAM_START_ADDRESS的赋值在头文件里,博客里没写出来,你可以下载附件看到,location是你定义变量的时候系统分配的

使用特权

评论回复
13
fhguo1990| | 2015-4-23 21:28 | 只看该作者
#define K60_SRAM_START_ADDRESS    (*(vuint16 *)(0x60000000))       /* 定义K60部分的外扩SRAM首地址 */    那数据不是要写到首地址开始的地址中吗?谢谢

使用特权

评论回复
14
我思故我在12345|  楼主 | 2015-4-23 21:28 | 只看该作者
fhguo1990 发表于 2015-4-23 21:28
#define K60_SRAM_START_ADDRESS    (*(vuint16 *)(0x60000000))       /* 定义K60部分的外扩SRAM首地址 */ ...

嗯,是的~

使用特权

评论回复
15
fhguo1990| | 2015-4-23 21:29 | 只看该作者
你设计这个电路时,有没有分析两个片子的时序?我看IS61WV102416读周期只需8ns,而K60最快的读周期也需要80ns,两者之间有没有问题呢,谢谢

使用特权

评论回复
16
我思故我在12345|  楼主 | 2015-4-23 21:29 | 只看该作者
fhguo1990 发表于 2015-4-23 21:29
你设计这个电路时,有没有分析两个片子的时序?我看IS61WV102416读周期只需8ns,而K60最快的读周期也需要80 ...

8ns是理论最快的读速度,再快的话读取就会出现问题,而如果慢些那肯定是没问题了,所以对K60来说80ns肯定是可以的啊~

使用特权

评论回复
17
fhguo1990| | 2015-4-23 21:30 | 只看该作者
我思故我在12345 发表于 2015-4-23 21:29
8ns是理论最快的读速度,再快的话读取就会出现问题,而如果慢些那肯定是没问题了,所以对K60来说80ns肯定 ...

明白了  谢谢

使用特权

评论回复
18
fhguo1990| | 2015-4-23 21:31 | 只看该作者
你好,FLEXBUS扩SRAM电路的,对于写指令的执行不太懂,想问一下,程序中怎么实现写入16位数据,比如指令
    wdata16=0x1234;                //data to write to mram
    *(vuint16*)(&K60_SRAM_START_ADDRESS) = wdata16;   //write
执行第二步时,K60地址线输出地址0x0000,FB_AD0接IS61WV1024160的UB/,此时变低,这时0x12写入IS61WV102416地址0x0000的高位,低位0x34是怎么写入的?非电子专业学生,希望指点!

使用特权

评论回复
19
我思故我在12345|  楼主 | 2015-4-23 21:31 | 只看该作者
fhguo1990 发表于 2015-4-23 21:31
你好,FLEXBUS扩SRAM电路的,对于写指令的执行不太懂,想问一下,程序中怎么实现写入16位数据,比如指令
    ...

将K60_SRAM_START_ADDRESS强制转换成了指向16位数据的指针,因此在写第二个字节的时候该地址会自动加1,地址输出线会变成0x0000_0001,选通LB,这样就将0x34写入了

使用特权

评论回复
20
fhguo1990| | 2015-4-23 21:32 | 只看该作者
我思故我在12345 发表于 2015-4-23 21:31
将K60_SRAM_START_ADDRESS强制转换成了指向16位数据的指针,因此在写第二个字节的时候该地址会自动加1, ...

谢谢!

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

27

主题

318

帖子

9

粉丝