uclinux-2008R1.5-RC3(bf561)到VDSP5的移植(68):PLL配置

来源:互联网 发布:txt小说下载软件 编辑:程序博客网 时间:2024/05/04 00:59

快乐虾

http://blog.csdn.net/lights_joy/

lights@hb165.com

  

本文适用于

ADI bf561 DSP

优视BF561EVB开发板

uclinux-2008r1.5-rc3(smp patch)

Visual DSP++ 5.0(update 5)

  

欢迎转载,但请保留作者信息

本文讨论链接:http://www.bfin-tools.org/bbs/viewthread.php?tid=20&extra=

 

在之前的处理中,只是简单地给B核一条idle指令,并让它先于A核运行,现在要开始使用B核了,自然这种方式就不好使了。

还记得ADI那个经典的Set_PLL吗?呵呵,看看:

void Set_PLL(short CoreCLOCK_multiplier, short SCLK_divider)

{ short previous_PLL= *pPLL_CTL;

  short previous_SICA_IWR = *pSICA_IWR0;

  short previous_SICB_IWR = *pSICB_IWR0;

  short new_PLL= (previous_PLL & 0x81ff) | ((CoreCLOCK_multiplier & 0x3f) <<9);

  

  if (new_PLL != previous_PLL) {            // skip if multiplier has not changed

             

      if ((int)(*pSRAM_BASE_ADDRESS) == 0xFF800000 ) {                            // do things for Core A

 

          *pSICB_SYSCR |= 0x0080;              // Raise Core B Supplemental-Int0

         ssync();

 

          while((*pSICB_SYSCR & 0x080)) {      // Wait: Core B Acknowledge SUP-B0

              asm volatile ("nop;nop;nop;nop;");

         }

               

          *pSICA_IWR0 = (previous_SICA_IWR | 0x1); // enable PLL Wakeup Interrupt

         *pPLL_CTL = new_PLL;

         ssync();

        

         idle();                                // put in idle

 

         *pSICA_IWR0 = previous_SICA_IWR;       // continue here after idle, restore previous IWR content

         ssync();

       }

     else{                                           // do things for Core B

 

         while(!(*pSICB_SYSCR & 0x0080))  {        // Wait: For Core A to raise SUP-B0

              asm volatile ("nop;nop;nop;nop;");

         }

        

         *pSICB_SYSCR = 0x0800;      // Acknowledge Supplemental Interrupt

         ssync();

    

         *pSICB_IWR0 = (previous_SICB_IWR | 0x1); // enable PLL Wakeup Interrupt

         ssync();

        

         idle();                                // put in idle

 

         *pSICB_IWR0 = previous_SICB_IWR;       // continue here after idle, restore previous IWR content

         ssync();

    

    }    // if (&_CORE == 0)

        

  }   // if (new_PLL != previous_PLL)

 

  *pPLL_DIV = (*pPLL_DIV & 0xFFF0) | SCLK_divider;

  ssync();

 

}

这段代码无非就是撇开SICA_SYSCR中的CoreB_SRAM_INIT这一位,改用SICB_SYSCR进行核间通信。因为在VDSPCoreB_SRAM_INIT这一位总是为0的,也就是说B核总是运行的。既然如此,我们干脆大方点,一开始就把这一位清0

看看SICB_SYSCR

SICB_SYSCR

再看看它的使用:

Core A can write “1” to Bit 6 of SICB_SYSCR to interrupt itself or to Bit 7 to interrupt Core B. Similarly, Core B can write “1” to Bit 8 of SICB_SYSCR to interrupt Core A or to Bit 9 to interrupt itself. Writing “1” to Bits 10, 11, 12, 13, respectively, would clear these interrupts.

现在我们学习它的这种方式,在B核启动的时候调用这个函数:

void wait_pll_setup()

{

     /* 等待A核进行PLL配置*/

    short previous_SICB_IWR = *pSICB_IWR0;

     while(!(*pSICB_SYSCR & 0x0080)) 

     {       

         // Wait: For Core A to raise SUP-B0

         asm volatile ("nop;nop;nop;nop;");

     }

        

     *pSICB_SYSCR = 0x0800;      // Acknowledge Supplemental Interrupt

     ssync();

    

     *pSICB_IWR0 = (previous_SICB_IWR | 0x1); // enable PLL Wakeup Interrupt

     ssync();

        

     idle();                                // put in idle

 

     *pSICB_IWR0 = previous_SICB_IWR;       // continue here after idle, restore previous IWR content

     ssync();

 

     // 等待真正的启动信号

     while(!(*pSICB_SYSCR & 0x0080)) 

     {       

         asm volatile ("nop;nop;nop;nop;");

     }

}

这段代码将首先等待A核的一个中断,然后进入IDLE状态,这样A核进行的PLL设置就可以生效了。然后进入第二次等待,等待真正的启动信号,这样B核才真正开始执行,这个启动信号将在A核启动完成后给出,也就是原来要将SICA_SYSCR中的CoreB_SRAM_INIT这一位清0的位置。

A核中,原来进行PLL配置是由这几行代码实现的:

       //p0.h = hi(PLL_CTL);

       //p0.l = lo(PLL_CTL);              /* Load the address                */

       //cli r2;                          /* Disable interrupts              */

       //ssync;

       //w[p0] = r0.l;                    /* Set the value                   */

       //idle;                            /* Wait for the PLL to stablize    */

       //sti r2;                          /* Enable interrupts               */

我们现在改用这个函数来完成:

void notify_pll_setup(unsigned int pll_value)

{

     short previous_SICA_IWR = *pSICA_IWR0;

     unsigned int mask;

    

     /* The default startup code does not include any functionality to allow core

        A to enable core B. A convenient way to enable core B is to use the

        'adi_core_b_enable()' function. */

     adi_core_b_enable();

    

     *pSICB_SYSCR |= 0x0080;              // Raise Core B Supplemental-Int0

     ssync();

 

     while((*pSICB_SYSCR & 0x080))

     {       

         // Wait: Core B Acknowledge SUP-B0

         asm volatile ("nop;nop;nop;nop;");

     }

               

     *pSICA_IWR0 = (previous_SICA_IWR | 0x1); // enable PLL Wakeup Interrupt

     ssync();

    

     *pPLL_CTL = pll_value;

     ssync();

        

     idle();                                // put in idle

 

     *pSICA_IWR0 = previous_SICA_IWR;       // continue here after idle, restore previous IWR content

     ssync();

}

这段代码将启用B核,然后给它一个中断,再等待B核的确认,最后再写入PLL_CTL

这样在VDSP下调试的时候,只要先运行B核就可以了。

搞定!

 

 

PS:突然想起某君的一篇论文,其实通篇就一句话:“用SICB_SYSCR进行核间通信”,居然也可以包装出一篇论文来,不得不让人感叹包装的力量,哈哈!!

1       参考资料

uclinux-2008R1.5-RC3(bf561)VDSP5的移植(63)_NSIG_WORDS_is_unsupported_size(2009-2-11)

uclinux-2008R1.5-RC3(bf561)VDSP5的移植(64)__ebss_b_l1(2009-02-12)

uclinux-2008R1.5-RC3(bf561)VDSP5的移植(65)B核启动(2009-2-13)

uclinux-2008R1.5-RC3(bf561)VDSP5的移植(66)_ebss_l1(2009-02-13)

uclinux-2008R1.5-RC3(bf561)VDSP5的移植(67)li1240(2009-2-14)

 

 

 

 

 

 

原创粉丝点击