
Wow, it's been almost 5 years and one pandemic since I tried to do something with this chip, first by installing, or rather piggybacking on, the gcc-avr toolchain. This MCU is pin compatible with the 8051 except for the polarity of the reset pin. I tried to get it working in the dev board in #Adventures with a STC89C52 development board but no joy.
Today I decided to try to get it working (or determine that it's bust) once and for all. I flashed a clock program onto it and watched the voltages on the port pins. All high. But the oscillator pins seemed to be ok. Time to look at my firmware.
Disassembling the .elf file with avr-objdump showed the start of the executable area:
Disassembly of section .text: 00000000 <__ctors_end>: 0: 11 e0 ldi r17, 0x01 ; 1 2: a0 e6 ldi r26, 0x60 ; 96 4: b0 e0 ldi r27, 0x00 ; 0 6: ea ef ldi r30, 0xFA ; 250 8: f6 e0 ldi r31, 0x06 ; 6 a: 03 c0 rjmp .+6 ; 0x12 <__zero_reg__+0x11> c: c8 95 lpm e: 31 96 adiw r30, 0x01 ; 1 10: 0d 92 st X+, r0 12: ac 32 cpi r26, 0x2C ; 44 14: b1 07 cpc r27, r17 16: d1 f7 brne .-12 ; 0xc <__zero_reg__+0xb> 00000018 <__do_clear_bss>: 18: 21 e0 ldi r18, 0x01 ; 1 1a: ac e2 ldi r26, 0x2C ; 44 1c: b1 e0 ldi r27, 0x01 ; 1 1e: 01 c0 rjmp .+2 ; 0x22 <.do_clear_bss_start> 00000020 <.do_clear_bss_loop>: 20: 1d 92 st X+, r1 00000022 <.do_clear_bss_start>: 22: a9 34 cpi r26, 0x49 ; 73 24: b2 07 cpc r27, r18 26: e1 f7 brne .-8 ; 0x20 <.do_clear_bss_loop> 00000028 <__vector_4>: 28: 1f 92 push r1 2a: 0f 92 push r0 2c: 0f b6 in r0, 0x3f ; 63 2e: 0f 92 push r0 30: 11 24 eor r1, r1 32: 8f 93 push r24 34: 80 91 37 01 lds r24, 0x0137 ; 0x800137 38: 81 50 subi r24, 0x01 ; 1 3a: 80 93 37 01 sts 0x0137, r24 ; 0x800137 3e: 8f 91 pop r24 40: 0f 90 pop r0 42: 0f be out 0x3f, r0 ; 63 44: 0f 90 pop r0 46: 1f 90 pop r1 48: 18 95 reti
Ah, that's no good. Although the code starts at 0, the next few locations should be interrupt vectors. In particular there should be an entry for vector_4, the timer vector. The code clears the BSS, but doesn't set up the PSW and the SP; one would expect some out 0x3[def] instructions. It doesn't call main, but falls through to vector_4, the first routine in the main C program.
We need more than this. Arduino users of the AVR chips have a startup environment that calls setup(), then loop() repeatedly. When doing bare metal (bare silicon?) stuff, like I am there should be startup code. Unfortunately a search on bare metal AVR got lots of pages explaining how to do direct I/O to ports, bypassing pinMode() and digitalWrite(), that's their idea of bare metal. The closest I found was this post on StackOverflow.
Ok so I need the equivalent of what has been known since Unix days as crt0.s, the assembly code for the startup code for C programs. A bit of searching in the avr-gcc directories found crtat90s8515.o. No corresponding .s, but that's ok, I can disassemble it with avr-objdump. It's probably in the source distribution.
Adding crtat90s8515.o to the list of linker input files gets this disassembled code:
Disassembly of section .text: 00000000 <__vectors>: 0: 0c c0 rjmp .+24 ; 0x1a <__ctors_end> 2: 27 c0 rjmp .+78 ; 0x52 <__bad_interrupt> 4: 26 c0 rjmp .+76 ; 0x52 <__bad_interrupt> 6: 25 c0 rjmp .+74 ; 0x52 <__bad_interrupt> 8: 25 c0 rjmp .+74 ; 0x54 <__vector_4> a: 23 c0 rjmp .+70 ; 0x52 <__bad_interrupt> c: 22 c0 rjmp .+68 ; 0x52 <__bad_interrupt> e: 21 c0 rjmp .+66 ; 0x52 <__bad_interrupt> 10: 20 c0 rjmp .+64 ; 0x52 <__bad_interrupt> 12: 1f c0 rjmp .+62 ; 0x52 <__bad_interrupt> 14: 1e c0 rjmp .+60 ; 0x52 <__bad_interrupt> 16: 1d c0 rjmp .+58 ; 0x52 <__bad_interrupt> 18: 1c c0 rjmp .+56 ; 0x52 <__bad_interrupt> 0000001a <__ctors_end>: 1a: 11 24 eor r1, r1 1c: 1f be out 0x3f, r1 ; 63 1e: cf e5 ldi r28, 0x5F ; 95 20: d2 e0 ldi r29, 0x02 ; 2 22: de bf out 0x3e, r29 ; 62 24: cd bf out 0x3d, r28 ; 61 00000026 <__do_copy_data>: 26: 11 e0 ldi r17, 0x01 ; 1 28: a0 e6 ldi r26, 0x60 ; 96 2a: b0 e0 ldi r27, 0x00 ; 0 2c: ea e2 ldi r30, 0x2A ; 42 2e: f7 e0 ldi r31, 0x07 ; 7 30: 03 c0 rjmp .+6 ; 0x38 <__do_copy_data+0x12> 32: c8 95 lpm 34: 31 96 adiw r30, 0x01 ; 1 36: 0d 92 st X+, r0 38: ac 32 cpi r26, 0x2C ; 44 3a: b1 07 cpc r27, r17 3c: d1 f7 brne .-12 ; 0x32 <__do_copy_data+0xc> 0000003e <__do_clear_bss>: 3e: 21 e0 ldi r18, 0x01 ; 1 40: ac e2 ldi r26, 0x2C ; 44 42: b1 e0 ldi r27, 0x01 ; 1 44: 01 c0 rjmp .+2 ; 0x48 <.do_clear_bss_start> 00000046 <.do_clear_bss_loop>: 46: 1d 92 st X+, r1 00000048 <.do_clear_bss_start>: 48: a9 34 cpi r26, 0x49 ; 73 4a: b2 07 cpc r27, r18 4c: e1 f7 brne .-8 ; 0x46 <.do_clear_bss_loop> 4e: 48 d2 rcall .+1168 ; 0x4e0 50: 6a c3 rjmp .+1748 ; 0x726 <_exit> 00000052 <__bad_interrupt>: 52: d6 cf rjmp .-84 ; 0x0 <__vectors> 00000054 <__vector_4>: 54: 1f 92 push r1 56: 0f 92 push r0 58: 0f b6 in r0, 0x3f ; 63 5a: 0f 92 push r0 5c: 11 24 eor r1, r1 5e: 8f 93 push r24 60: 80 91 37 01 lds r24, 0x0137 ; 0x800137 64: 81 50 subi r24, 0x01 ; 1 66: 80 93 37 01 sts 0x0137, r24 ; 0x800137 6a: 8f 91 pop r24 6c: 0f 90 pop r0 6e: 0f be out 0x3f, r0 ; 63 70: 0f 90 pop r0 72: 1f 90 pop r1 74: 18 95 reti
Much better. The vector table is there now, the reset vector points to the startup routines, and vector_4 points to the timer ISR. The routine ctors_end initialises the PSW to 0, and the SP to 0x25f, the last location of RAM. There are routines to clear the BSS and copy constant data to initialised globals. Finally it does a rcall to 0x4e0, the address of main.
I flashed this to the chip and measured the pin voltages again, and got more plausible values. Ok, I'll take the win for this skirmish and test it again after I have connected up the display board.
Update 2025-03-22, round 2:
Well, I didn't quite totally win the last skirmish. It turned out that the voltages were not as expected as I had hastily measured them with a multimeter and thought that a voltage in the middle of the 0 to 5 V range indicated pulsing. A probe with a DSO showed that this wasn't the case.
So the fault lay somewhere in the MCU specific initialisation code since the rest of the code is generic and works on the 8051 family MCUs.
I first tried getting the simulator under MPLAB-X working, but it seems there is no debug model for the AT90S8515 any more, it's too old.
So it was back to scrutinising the code carefully. I'll cut to the chase and show you the diff, then explain.
--- at90s8515.c.orig 2025-01-18 15:39:24.285494723 +1100
+++ at90s8515.c 2025-03-22 21:48:05.804314906 +1100
@@ -11,7 +11,9 @@
void ports_init(void)
{
DDRC = 0xFF; // all output
+ PORTC = 0xFF; // all segment outputs high
DDRA = 0xFF; // all output
+ PORTA = 0xFF; // all digit outputs high
DDRD = 0x00; // all input
PORTD = 0xFF; // input pullup activated
DDRB = 0xFF; // all output, to start
@@ -21,12 +23,12 @@
{
TCCR1B = 0x00; // stop counter
TCCR1A = 0x00; // disconnected from output pin, no PWM
- OCR1BH = COUNTDIV >> 8;
- OCR1BL = COUNTDIV & 0xFF;
+ OCR1AH = COUNTDIV >> 8;
+ OCR1AL = COUNTDIV & 0xFF;
TCNT1H = 0x00; // start at 0
TCNT1L = 0x00;
- TCCR1B = CTC1 | 0x02; // clear counter on match, CK/8
- TIMSK |= OCIE1A; // enable timer interrupt
+ TCCR1B = (1 << CTC1) | 0x02; // clear counter on match, CK/8
+ TIMSK |= (1 << OCIE1A); // enable timer interrupt
sei(); // enable global interrupt
}
@@ -34,8 +36,8 @@
{
TCNT0 = (256 - 5); // 5µs -> 200 kHz -> 5 counts @ 1 MHz
TCCR0 = 0x02; // CK/8
- while ((TIFR & TOV0) == 0)
+ while ((TIFR & (1 << TOV0)) == 0)
;
- TIFR |= TOV0;
+ TIFR |= (1 << TOV0);
TCCR0 = 0x00; // stop counter
}
The first two changes are simply to set the output ports to high level which is not the power on default so that I know ports_init() is working.
The next 2 line change is because I was using the wrong timer compare register, it should be A. B doesn't have reset to 0 on match so isn't suitable.
The remainder of the diffs are because I had wrongly assumed that the symbols CTC1 and so forth from the include files were bitmasks. They are actually bit positions in the byte hence the edits to (1 << CTC1) and so forth.
With the new image flashed onto the MCU, I can now see the correct waveforms on the digit and segment select lines. Now to connect the board to a display.
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.