This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

This should be easy.....

I just started writing a C application for the Cygnal C8051F125 and am having difficulty setting/viewing the paged SFR's

Here's a simple example in C code:

SCON0=0x50;
SCON1=0x40;

Compiles fine, but when when I open the disassembly window, these 2 statements get translated to:

MOV SCON0(0x98),#0x50
MOV SCON0(0x98),#0x40

i.e., both statements modify SCON0. This is confirmed by opening the peripheral window and examining Serial port 1 and 2 --- SCON1 never changes (?????)

I understand the SFRs on the chip are spread over 5 pages, sharing common "base addresses" (0x98 in this case), but how do I access a specific page? And how do I view the different pages in the memory window?

This CAN'T be a bug, so what am I doing wrong?

Thanks,

Joe

  • The addresses of SCON0 and SCON1 are the same (0x98). When the disassembler looks at the instruction in memory, it's going to see exactly the same sequence of bytes for both instructions:

    0x75 0x98 0xdd

    Which SCON did I have in mind when I wrote that sequence? How do you know?

    The disassembler is smart enough to look into the symbol table and find a symbol that matches the address in this instruction: 0x98. But it doesn't know _which_ 0x98 was originally in the source. I imagine it just goes with the first match in the symbol table. (You'll see this sort of behavior from many debuggers, particularly near address 0 where you tend to have lots of small constants defined.)

    They could make the disassembler smart enough to read the full symbol information and make the results of the symbol lookup dependent on the context of the source line number. But then, that's why you have source level debuggers.

  • I can understand the problem the dissassembler has, but why does uVision even bother to have Serial 1 and Serial 2 peripheral windows if, when the code is executed, it doesn't accurately reflect the current settings? Typing "SCON1" in the command window also reveals the wrong value.

    This is different than a dissassembler problem, no? The simulator appears not to even know the current settings of these (and many other) SFR's.

    I thought the mechanism Cygnal provided for accessing "non-base-page" SFRs was using the SFRPAGE SFR, e.g., to change SCON1 you first set SFRPAGE to 1, then write to register 0x98. Setting SFRPAGE to 0 and repeating the write modifies SCON0. Accordingly, I expected the statement:

    SCON1=0xdd

    to be translated to:

    MOV SFRPAGE, #1
    MOV #0x98,0xdd

    C51 translated it as just 2 MOVs to the same address (no SFRPAGE changes).

    I don't see how this can possibly execute properly on the processor?????

    Have I got something wrong?

    Thanks,

    Joe

  • You're asking the compiler to know that you are referring to a paged SFR. Until Keil adds "Paged SFR" to its keywords, you have to do the paging yourself. Don't forget to restore the page to its original value.

    About the 2 windows... not all derivatives use paged SFRs.

  • The paged SFR mechanism is an interesting little quirk tossed in by Cygnal for this part. Most 8051 derivatives don't operate this way; I'm used to seeing SCON1 show up as SFR 0xC0, for instance.

    If the compiler were to be this smart about this particular vendor extension, yet another keyword extension would probably be the way to go, rather than depending on the name of the symbol. You'd need declarations something like:

    sfr SCON0 = 0x98 page 0;
    sfr SCON1 = 0x98 page 1;

    (Currently, I imagine the reg.h file for this part has declarations like the above without the "page" keyword I just made up, so SCON0 and SCON1 are just two names for the same register.)

    In the meantime, perhaps a macro is the way to go. (A macro, rather than function, in hopes that the optimizer can take out the repetitive calls to setting the SFR page. Otherwise, you're better off doing it by hand.)

  • So to put this to rest you are saying..

    1) I can't setup any peripheral on C8051F12x processors with "non-base page" SFR's in C code

    2) To set up any of these SFR's i'll need to do it in assembly, like:

    (save current SFR page#)

    MOV SFRPAGE, <SFR page number>
    MOV #<SFRREG>,<0xdd>

    (restore SFR page number)

    3) Ignore the peripheral dialog for this device and the one for the corresponding base page (because it gets confused by the write to the upper SFR).


    4) Probably alot of other work-arounds....

    I suppose I can do all that. My only beef is that the Keil site lists no such restrictions on these peripherals. In fact they say "The following on-chip peripherals are simulated by the Keil Software uVision Debugger" ..and goes on to list every peripheral except flash memory - misleading at the least.

    Buyer beware?

  • I thought my previous answer to this question answered all these questions: http://www.keil.com/forum/docs/thread3024.asp

    Anyway, the simulation description for the Cygnal C8051F125 (http://www.keil.com/dd/chip/3474.htm) includes the following note:

    NOTE
    Simulation for this device is provided by the default peripheral simulation driver. Complete on-chip peripheral simulation is not available at this time.

    For each simulation DLL we create, there exists a default driver that is intended to be a catchall for those devices that are not explicitly simulated. This works better in some cases than in others.

    Maybe you guys can help us come up with the best text to use that clearly states that the default simulation driver is used (and that it may not match the device 100%). As far as I can tell, Cygnal parts have the greatest deviation from the default driver.

    Jon

  • You CAN set the registers in C code. You can set any registers, including the Page register, which is just another SFR. There is no need to use assembler, but also nothing wrong with using an assembler routine to push/pop the page before/after changing it.

  • You can still access the sfr's from C, without using assembly. It'll just take you two statements.

    SFRBASE = 1;
    SCON1 = 0x50;
    

    If that seems like too much trouble, or too likely to split the lines, a function or macro would solve the problem. If all the SFRs happen to be declared appropriately (and you could always change the reg.h file if they weren't), you might even get some mileage out of the token-pasting operator.

    #define PagedSfr(name,page)    SFRBASE = page, name##page
    

    That's off the top of my head, and untested, perhaps a bad idea since I don't use the comma operator a lot. But it looks like it'll work in two major contexts:

       val = PagedSfr(SCON, 1);
       PagedSfr(SCON, 1) = val;
       PagedSfr(SCON, 0) = val;
    

    Though it might be simpler and easier to have a read and a write macro. You also might prefer to return the SFR page register to its previous state, or a known state (0), after every write, to avoid possible confusion.

    None of that helps you with the simulator, of course.

  • I would also like to nominate this thread for "Best Descriptive Title"