S12C32 - Code runs with PE BDM but not stand alone

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

S12C32 - Code runs with PE BDM but not stand alone

5,054 Views
tabull
Contributor I
I'm not sure where to post this question. My application fragment uses CW 5.7.0 and 6.1 debugger. I am using a Tech Arts NANOCoreMAX with a 9S12C32 and a P&E Micro USB Multilink BDM.

I have written C code to write to an LCD using the SPI and a 74HC595 latch. When I run this code using the BDM everything works fine. When I try to run the code with the BDM disconnected (I disconnect the power to the Tech Arts module, remove the BDM cable, reconnect power to the Tech Arts module, then push the reset button on the docking module) I get garbage on the LCD. But always the same garbage in the same sequence.

Obviously I am missing something here. Is it because I must change some settings to run without the BDM? Are there perhaps timing issues? The 9S12C32 is clearly running, and there is some kind of communication with the 595, and with the LCD, but it is not working right.

Thanks for any help. I am not a professional programmer or hardware designer. I am a ChE, entirely self-taught regarding micros, so I may be considered naive.

Dan
 
--
Alban Edit: Please always include FSL Part Number in Message Subject line.
http://forums.freescale.com/freescale/board/message?board.id=FORUMUSE&message.id=865


Message Edited by Alban on 2007-10-18 06:56 PM
Labels (1)
Tags (1)
0 Kudos
23 Replies

1,256 Views
CompilerGuru
NXP Employee
NXP Employee
Check the COP and also look out for write once registers.
Those things behave differently with/without bdm programmer.

Daniel
 
 
--
Alban edit: added S12C32 to title


Message Edited by Alban on 2007-10-18 06:57 PM
0 Kudos

1,256 Views
tabull
Contributor I
    The only registers explicitly written are SPIDR, DDRM, DDRT, SPICR1, SPICR2, and SPIBR. All of these can be written anytime.  I also read SPISR, but I do not write to this register, and in any event I believe writes to this register have no effect. Is there some other way such write once registers could be written to? Could there be some register I should be writing to use the SPI that I have missed?

Thanks,
Dan
0 Kudos

1,256 Views
JimDon
Senior Contributor III

Are you sure that you actually flashed the program?
I know it sounds pretty obvious, but if you were running the program from RAM it would work with CW and the BDM, but not at all after you reset the board.

If you want to, post the project.





0 Kudos

1,256 Views
tabull
Contributor I


JimDon wrote:

If you want to, post the project.




I'm still having no success with this problem.  As you suggested, I'm posting the project main.c. Maybe someone will see something I missed or a goof.

Thanks,
Dan
0 Kudos

1,256 Views
JimDon
Senior Contributor III


Well this is a long shot, but try a long delay at the start of the lcd init code, like 100 ms, and 100 ms again after the first command. I don't know what lcd controller you are using but I seem to remember something to that effect.

If no one finds anything else it might be helpful to also post the prm file as well.



Message Edited by JimDon on 2007-10-19 04:56 PM
0 Kudos

1,256 Views
tabull
Contributor I


JimDon wrote:


Well this is a long shot, but try a long delay at the start of the lcd init code, like 100 ms, and 100 ms again after the first command. I don't know what lcd controller you are using but I seem to remember something to that effect.

If no one finds anything else it might be helpful to also post the prm file as well.



Message Edited by JimDon on 2007-10-19 04:56 PM

Thanks for the suggestion. Unfortunately, it didn't work. The lcd is a Noritake vacuum fluorescent unit with an Itron controller which is supposedly 100% compatible with the HD44780.

Here is the prm file. Now you're getting completely out of my league.

Thanks,
Dan

0 Kudos

1,256 Views
JimDon
Senior Contributor III
Well, the prm look fine. BTW Your code looks good too, don't count yourself out as a good programmer.
Let me ask you this - I think I have not been picturing this right.

If you leave the BDM plugged in as though you were going to debug, but do not run the debugger, can you reset the board and have it run ok?



0 Kudos

1,256 Views
tabull
Contributor I


JimDon wrote:

If you leave the BDM plugged in as though you were going to debug, but do not run the debugger, can you reset the board and have it run ok?




Just to make sure I covered all permutations and combinations, I did the following:

1. Boot the PC. Plug in the BDM. Push reset on Tech Arts docking module.
    Result: Each reset causes one character to be written to the lcd. Cursor appears to move right one character each time. The one character is always the same. Looks like 0xFF except one pixel remains dark (row 3, column 4).

2. Boot the PC. Start IDE. Start debugger and run program. Program "works." Push reset on Tech Arts module.
    Result: The command window on the debugger writes that "Trigger C occurred," but only on the first reset. Each reset briefly displays the last character written, e.g. the "o" at the end of "hello," then writes a single character, always in the following sequence: 0x6F, 0xDE, 0xBC, 0x50, 0xE0, then two characters, first a character I cannot find in the Noritake table, but 0xC0 comes closest, and 0x80. After that, each reset generates the same character as in ex. 1, 0xFF with one dark pixel. Each character is displayed to the right of the previous character, that is, the characters are not overwritten.

3. Boot the PC. Start IDE. Start debugger and run program. Disconnect power from Tech Arts module. Reconnect with BDM still connected. Push reset on Tech Arts.
    Result: Same as in example 1, except the character is 0xFF with pixels in row three, columns 1, 2, and 4 remaining dark.

4. Boot the PC. Start IDE. Start debugger and run program. Program "works." Reset debugger (Ctrl R) Push reset on Tech Arts module.
    Result: Same as ex. 3.

5. Boot the PC. Start IDE. Start debugger and run program. Program "works." Reset debugger (Ctrl R)  Run program (F5).
    Result: No output to lcd.  Push reset on Tech Arts module.
    Result: Same character sequence as ex. 2.

6. Boot the PC. Start IDE. Start debugger and run program. Program "works." Reset debugger (Ctrl R)  Run program (F5).
    Result: No output to lcd. Push Ctrl R and F5 again. Program runs normally. Push reset on Tech Arts module.
    Result: Same as ex. 3.

I don't know if any of this has any meaning whatsoever, and I hope I'm describing what I did accurately, but I'm just throwing it out there.

Thanks,
Dan
0 Kudos

1,256 Views
tabull
Contributor I
    Well, folks, I've figured it out.

Seems that the SPI flag was not cleared on reset. I simply added three lines of code to the SPI initialization routine SPI_Set():

volatile unsigned char status, data;

at the beginning of SPI_Set() and

status = SPISR;
data = SPIDR;

at the end.

Voila, everything works as it should.

Thanks to all for so much help. I learned a few new things, and got some good programming and hardware setup tips.

Thanks,
Dan

0 Kudos

1,256 Views
bigmac
Specialist III
Hello Dan,
 
This SPI issue seems to also be common with HCS08 devices, for which there has been previous discussion in the following post, and the link within the post -
 
Two alternative methods are discussed, to achieve reliable operation of the SPI module.  During initialisation, it is only necessary to read SPISR to alleviate the problem.  A possible reason that the problem does not appear during debug is that SPISR is likelly periodically read during the debugging process.
 
Regards,
Mac
 
0 Kudos

1,256 Views
tabull
Contributor I
    JimDon wrote:

Are you sure that you actually flashed the program?
I know it sounds pretty obvious, but if you were running the program from RAM it would work with CW and the BDM, but not at all after you reset the board.

If you want to, post the project.
===========
It was flashed.  If it were running from RAM, then nothing at all would happen with the BDM disconnected, but in fact, I do see output to the LCD.

It is 10:30 PM here in MA, but I will post the project in the AM.

Thanks,
Dan
0 Kudos

1,256 Views
Lundin
Senior Contributor IV
Checklist:

- Is the oscillator running at the correct frequency? If you are using the PLL, is the filter and register settings working, ie is it locking properly?

- Do you have a pull-up resistor on the reset line? Do you have one on BKGD/MODC (assuming normal single chip mode)?

- Do you have a capacitor with high capacitance (>100pF) on the reset line? Do you have one on BKGD/MODC?

- Who sets the stack pointer, you or start12.c? Is it set to the right address?

- Are you writing explicitly to INITRG, INITRM, INITEE or do you use the default setting?

Checking write-once registers is a good idea. Here is a list of all write-once (or partial write-once) registers in the S12:

000A PEAR
000B MODE
000E EBICTL
0010 INITRM
0011 INITRG
0012 INITEE
0013 MISC
001E INTCR
0039 CLKSEL
003C COPCTL
00E8 DLCBCR1
00EC DLCBARD
00ED DLCBRSR
0100 FCLKDIV
0110 ECLKDIV
0141 CAN0CTL1
0181 CAN1CTL1
01C1 CAN2CTL1
0201 CAN3CTL1
0281 CAN4CTL1
0 Kudos

1,256 Views
tabull
Contributor I
    Checklist:

- Is the oscillator running at the correct frequency? If you are using the PLL, is the filter and register settings working, ie is it locking properly?

I am running at 4 MHz, and I am not using the PLL.

- Do you have a pull-up resistor on the reset line? Do you have one on BKGD/MODC (assuming normal single chip mode)?

There is a 10k pullup on RESET and 4.7k on BKGD/MODC.

- Do you have a capacitor with high capacitance (>100pF) on the reset line? Do you have one on BKGD/MODC?

Not that I can detect. I certainly did not intentionally add one.

- Who sets the stack pointer, you or start12.c? Is it set to the right address?

The stack is initialized by start12.c. It is set to 0x900.

- Are you writing explicitly to INITRG, INITRM, INITEE or do you use the default setting?

I do not intentionally write to any of these.

Regarding your list of write once registers, I do not write to any of them, including COPCTL, which I believe is set to 0x00 (COP disabled) on reset.

Thanks,
Dan

0 Kudos

1,256 Views
Lundin
Senior Contributor IV
Ok, so the problem here was the SPI. Still, there are some things your should consider as good design practice:

In order to be immune to EMI/noise, you need a decoupling capacitor on the reset line. 47pF or 100pF are common values that work well. Larger values will give you problems, since the HCS12 requires a rather quick reset edge. The pull-ups are also necessary.


When using start12.c, avoid using the "zero out" functionality that sets all your global/static variables to zero. The only reason it's there, is because ANSI/ISO C demands it. C was however designed for RAM-based systems.
In an embedded system, you should setup the initial values yourself, just before one particular module of your program is used. This will prevent the program from using corrupted RAM. Depending on the application, it may take years from reset to the use of a particular variable.

For the same reason, you should write to the registers you are using on regular basis, since they are also RAM cells. And make sure to set up every write-once register that affects the application.

I recommend getting rid of start12.c entirely, to make your program safer and quicker, although it will not work with ANSI-C compatible code that uses static initialization. An example of a reset vector:

#pragma TRAP_PROC
void interrupt_reset(void)
{
#pragma MESSAGE DISABLE C12053 /* LDS warning */
asm LDS #$2100;

INITRG = 0x00;
INITRM = 0x21;
INITEE = 0x09;

(void) main();
}


int main()
{
#pragma MESSAGE DISABLE C12053 /* LDS warning */
asm LDS #$2100;

}

Comments:

- Set up the stack to get the function call of main() right.
- Set up init registers properly, especially if using another memory map than the default.
- CALL/BSR will leave junk on the stack. Since you will never return to the reset vector again, clear the stack from main(). Note that start12.c leaves junk on the stack as well - so you always need to clear the stack the first thing you do in main().
0 Kudos

1,256 Views
CompilerGuru
NXP Employee
NXP Employee
Just a few notes.
- using asm LDS #$2100;
in the start of main is not safe, if main is using local variables, then the compiler will allocate the variables before the LDS, the net effect is that the locals will be accessed above $2100, say outside of the designated stack space.
If main does not use locals (and the compiler does not allocate some internally either for spills for the code generated in main), then  the LDS will actually work, but as it is a rather advanced optimization, I would be careful doing it, definitely its nothing for the beginner.
- start12.c does does actually put the return address on the stack for the banked memory model, but not for the small memory model though, where the existing code in start12.c ends with a JMP main. For banked, it's correct that those 3 return address RAM bytes could be avoided, but that's an advanced topic. Doing it in start12.c is possible, but the code gets more complex as it has to jump with a RTC instead of a simple call main.

Daniel

0 Kudos

1,256 Views
Lundin
Senior Contributor IV
Yes, you would obviously have to set the local variables in main() to static. Even though 2-3 bytes of RAM data lost is likely not a big issue in most programs, to the purist it does look rather bad that the first thing done in every "banked" program ever written in CW is a permanent memory leak.

If you don't want to use static for the main() locals, for some strange reason (main() is after all the bottom level of the program), a somewhat acceptable solution would be for the reset isr to CALL a routine in the same page as main(), set the stack from there and then JMP to main.

Anyway, the main points with my post are that one should update RAM registers frequently and get rid of static initialization to increase the safety of the program. Aand thereby getting rid of unnecessary startup lag as a bonus. Plus, start12.c is written in compiler-switch gibberish, if you get rid of the file you don't have to bother interpreting it to understand what your program actually is doing when it starts.
0 Kudos

1,256 Views
JimDon
Senior Contributor III
I don't want to start a flame thread, but if you are a beginner, please do not get rid of start12.c.

It could be said that doing that will make it less safe, as now initialized global variables will not longer be initialized automatically.

We could go back and forth about this, but the savings to be had are minimal, and you have many other things to focus on rather than re-writing the startup code. The Code Warrior folks  have done a great job of this, and it is unlikely you, as a beginner will do any better.


I
0 Kudos

1,256 Views
Lundin
Senior Contributor IV
If you are a beginner you shouldn't design real-time/automotive/safety-critical systems in the first place. We have to assume that the vast majority of the users are experienced programmers who know how to write programs for the typical applications HCS12 is ment to be used for.

Static initialization is not safe, that is a known fact. It is there because the ISO C standard says so, and that standard was written for RAM-based systems in office environments. If you are designing consumer electronics or hobby projects, yes, it will suffice.

Removing the static initialization will hardly make the program less safe: if you have bugs in your program relying on the zero value in your global variables, wouldn't it be better to find those bugs instead of never noticing them before disaster strikes? Which is what will happen when the RAM gets corrupted after weeks of uptime.
0 Kudos

1,256 Views
JimDon
Senior Contributor III
"Static initialization is not safe, that is a known fact."

Presumably you are referring to C++ static initialization order of classes race condition, as this is the only know problem with static initialization, and even in C++ is easily preventable if you know what you are doing.

Not to worry - won't happen here. You aren't using classes with constructors, and all initialization will be be done before any of your code executes. Also, since interrupts are off there are no threading issues.

Just to correct another item, the start up code does more than just zero out locations. It is a well accepted principle of correct coding practices that a know starting value for variables is a good thing.

As has been said, our job is to inform, not mislead.

0 Kudos

1,256 Views
Lundin
Senior Contributor IV
I'm not talking about C++, though things get worse there with constructors. I'm talking about how to avoid hardware weaknessess with software code. As I wrote in the first post:

"In an embedded system, you should setup the initial values yourself, just before one particular module of your program is used. This will prevent the program from using corrupted RAM. Depending on the application, it may take years from reset to the use of a particular variable."

Everyone who design safety-critical systems does that, hence the "known fact", because RAM can't be trusted to keep its values over long time periods. It is not a programming problem, it is an electronical problem: RAM values are of a volatile nature. We are still talking about systems that run in tough environments here. Things that work on a PC and that are concidered as good programming on a PC, aren't necessarily good in an embedded system controlling the breaks of your car.

Message Edited by Lundin on 2007-10-25 08:59 AM
0 Kudos