AnsweredAssumed Answered

Why my BF561 program won't wake up after PLL change?

Question asked by Yaniv.Sapir on Jun 25, 2011

This post is intended to summarize my experience from the past few days in developing a project on a BF561 dual core processor. It is meant as a reference for future questions on this subject, and for users having difficulties with the new multicore concept.

[Scroll down for the short version]


I started with a project that was developed for the BF533 single core processor. The program had a PLL clock rate change and utilization of the UART for transmitting data to the PC. At first, I just changed the processor type of the project to the BF561, assuming that the project should be migratable as-is. It happened not so.


Digging into the debug we noticed that the program is never goes past the idle; instruction after the PLL_CTL reg change. Moreover, no interrupt was latched in the ILAT register (we expected to get the PLL_Wakeup interrupt when the clock settles). The obvious thing to do was to set bit #7 of IMASK and bit #0 of SICA_IMASK0, to let the iterrupt pass from the PLL to CoreA. This however, did not help as well.


Next, I found in the BF561 hardware documentation, at the "PLL Programming Sequence" section, the following information: "Note: In order to program the PLL, both cores must be in an idled state." ; At the "Booting Methods" section, I found: "At power up or after a hardware reset event, Core A comes out of reset and executes the boot kernel code at address 0xEF00 0000. Core B is held in the idle state." ; This means that the simple code imported from BF533, with the changes made so far, should have worked - but it doesn't.


I then decided to start a new project from scratch, this time using the Project Wizard to generate the template for a "Single Core: Single Application" type of application. Upon selecting this type (the firs of the four types), a pop-up messagebox appeared saying that when using Emulation, Core B is always enabled! [see full message in attached image file]. This means that contrary to what's written in the hardware manual, the PLL setup process will never take place due to Core B not being in Idle mode! This is why the Wizard suggests using project type "Dual Core: Single Application" and a supplemental code for idling of Core B is produced.


After adding the actual code from the original project into the newly generated project template I tried running the application (with CTRL+F5 command, not just F5). As expected, the wakeup interupt did fire. Surprisingly, though, Core A jumped to an unknown exception immediately after waking up...


Further investigation showed that the problem was the enablin of the relevant IMASK bits. When the wakeup interrupt was received in the core, an attempt to service it was made, but the vector table was populated with the unknown exception address. The last fix we had to do was to disable all interrupts but the PLL_Wakeup in the SICA_IWR register and block ALL interrupt requests with the IMASK register. This way, the cores go into idle state and only the PLL wakeup signal can release them - while not being serviced by the sequencer.


To summarize a long story:


1. Use Project Wizard to generate a template for a Dual Core project.

2. In you PLL code, save the IMASK register state and clear it using: imask = cli();

3. Disable all IWR interrupts but PLL_Wakeup (bit #0)

4. Set the PLL_CTL register

5. Call ssync() and idle()

6. Modify PLL_DIV if required.

7. Restore IMASK using sti(imask);


Here's an example:


void init_PLL(int df, int msel, int ssel, int csel)
    unsigned int imask;
    *pSICA_IWR0 = 0x01;
    *pSICA_IWR1 = 0x00;
    imask = cli();
    *pPLL_CTL = (*pPLL_CTL & 0x81fe) | ((msel << 9) | (df));
    *pPLL_DIV = (*pPLL_DIV & 0xffc0) | ((csel << 4) | (ssel));