• Please review our updated Terms and Rules here

8051/8052 SBC

Yes, I'm using the Atmel AT89S52 - and I mentioned above about how I programmed a fast ICSP programmer for it, using an Arduino to talk to its SPI pins. You just use an XMODEM transfer of an Intel Hex file to the Arduino's serial port, and it does the rest. The S52 is only a 12T design, though. The AT89LP version runs two or three times as fast, according to the data sheet - though I've not tried one, yet.

My Atmel S52 chips are the 24PU type - I run them with 22.1184 MHz crystals, but I've not tried pushing them beyond that.

The STC chips will run with 40 MHz crystals, and at 6T, but I've still not been able to find a seller of the HC versions - either PDIP 40 or LQFP 44 packages.

There are lots of other 8051 core chips in the STC family - and some of those run at 1T and high frequency clocks, but only the '89' version (as far as I know) supports external memory - either RAM or ROM. I've used STC15, STC12 and STC8. The STC8 ones are the fastest, if you don't need external memory.
 
Looks interesting. I also have a Silicon Labs C8051F340 dev board. That chip has 64K flash, and 4K onboard RAM. It runs at 1T (up to 48 MIPS), has an internal precision oscillator and has many built in peripherals - USB, SPI, I2C, A/D, etc. It supports external memory, but will not run code from anywhere except its own internal 64K flash.

I really ought to try MCS-BASIC on that C8051F340 - it could possibly run just on the standalone chip? In any case, the dev board has a nice pin out on a 0.1-inch grid, so it would be easy to make a strip board 'shield' to fit it with extra RAM. For some reason, I keep getting drawn back to the old STC chips - I don't know why when there are more modern and faster alternatives available.
 
I've attached my Game of Life program. This one should work on any system that has somewhere in its memory space where data memory is also mapped as code memory. Example gertk's system, which I think he said has such memory up at E000h

It initially 'pokes' the machine code to the area from 7E5Ch up to 7FD1h (with a little data table after that). But then it checks if the same bytes can be seen in the code space at those same addresses - if not, it asks you where you'd like to move the code to, and copies it over - then it self-modifies the CALL addresses to match, and patches the GOSUB that does the "move required?" check, so that it isn't called again on subsequent runs.

You only need the gol.b52 (BASIC) program, but I've included the assembler source for the machine code, in case anyone is interested. Also, if you have a system with no shared data/code space, you might still be able to run the program by burning the machine code to EPROM, and patching the two CALL statements to the correct addresses.

It's best to set the baud rate as high as your system can go, because the program is mostly speed limited by the rate at which it can update the screen.
 

Attachments

I've attached my Game of Life program. This one should work on any system that has somewhere in its memory space where data memory is also mapped as code memory. Example gertk's system, which I think he said has such memory up at E000h
That is correct, 8kB from E000h-FFFFh
It initially 'pokes' the machine code to the area from 7E5Ch up to 7FD1h (with a little data table after that). But then it checks if the same bytes can be seen in the code space at those same addresses - if not, it asks you where you'd like to move the code to, and copies it over - then it self-modifies the CALL addresses to match, and patches the GOSUB that does the "move required?" check, so that it isn't called again on subsequent runs.
Seems to work, program runs ok
You only need the gol.b52 (BASIC) program, but I've included the assembler source for the machine code, in case anyone is interested. Also, if you have a system with no shared data/code space, you might still be able to run the program by burning the machine code to EPROM, and patching the two CALL statements to the correct addresses.

It's best to set the baud rate as high as your system can go, because the program is mostly speed limited by the rate at which it can update the screen.
Indeed, at 9600 baud (my default setting) it is updating slowly.
Color scheme for the menu seems to be 'off' in Minicom and after some iterations the cursor re-appears.
Have to check if the upload went wrong or something else.
Also found out that my SAVE"filename" only saved up about 4kB, looks like it found an 'end of basic program' signature prematurely.. :-)

Anyway good test material!
 
SAVE is fixed now, I now am using the system LEN function to determine the size of the program, add the start of the Basic program to it and then use that as 'end of program' value
:)
 
I tried it with gtkterm under Linux, and Teraterm with Windows, and the colours look okay to me. I'll have a look at the colours with Minicom. I tried to use the standard yellow, blue, black and green ANSI colours, unless I've made a silly mistake...

I find I can run reliably at 115200 baud with a 22.1184 MHz crystal, and no character pacing delay is needed for uploads. I use a macro I wrote for Teraterm, or the same idea in my own terminal program under Linux, that waits for a "linefeed >" combination before sending the next line during uploads, so I don't need any line delays either. Actually, at 22.1184 MHz, I can push the baud up to 230400, but then I do need a small character delay when uploading.

Obviously, with an 11.0592 MHz crystal, all those baud rates are halved.

By the way, I should have said that my assembler source is in the sdas8051 assembler dialect. This is one of the assemblers that ship with SDCC - the great, free, C compiler for 8051 and lots of other retro chips. I'm familiar with that assembler because it's the one used by SDCC when you want to put some snippets of inline assembly in your C code - and the compiler itself generates an asm file first, which it runs past the assembler to produce the Intel Hex files. I think sdas8051 is a slight variation of one of the ASxxxx cross-assemblers, written by Alan Baldwin, and others.

I've not tried writing C routines for MCS-BASIC yet. I think it would be hard work, as both BASIC and the C compiler produced code take over a lot of the chip's internal low memory - I think you'd end up having to copy a load of stuff over to XRAM, set up the memory for C to run its routine, and then restore from XRAM to low memory before handing back to BASIC - it would make for a slow handover if you were accessing frequently-used C functions. For the Game of Life I just went with 100% handwritten assembly.
 
Semi-related tangent: How much "better" is the MCS51 as compared to the MCS48 (or whatever it's called, the 8748/8048)?

If there is any chance of porting the software you all are writing/using in this thread over to the 8048 you might be able to finally after about 4½ decades have a decent basic for the Videopac G7000 / Magnavox Oddysey 2, with it's full alphanumeric membrane keyboard and whatnot.
 
Have now tried Minicom. Agree that the colours are horrible. What should be blue text is rendered in a sort of bright cyan, which makes it difficult to see against the yellow(ish) background.

Try installing and running gtkterm - a pretty lightweight terminal emulator compared to Minicom. That seems to render the colours properly.

I can't find any way to edit the Minicom ANSI colours.
Actually, Minicom works better in VT102 mode than ANSI, where it doesn't properly clear the whole screen to the background colour - only the printed character areas. And I still had to do tricks from the command line: minicom -c on
Why isn't that setting part of Minicom's normal configuration, where it remembers what serial port to use, and such?
 
Semi-related tangent: How much "better" is the MCS51 as compared to the MCS48 (or whatever it's called, the 8748/8048)?

If there is any chance of porting the software you all are writing/using in this thread over to the 8048 you might be able to finally after about 4½ decades have a decent basic for the Videopac G7000 / Magnavox Oddysey 2, with it's full alphanumeric membrane keyboard and whatnot.
The G7000/Odyssey 2 is not capable of running Basic since there are only 128 bytes of RAM available, Also the videochip can not display a full screen of text without doing some major tricks (like multiplexing the 4 'quads' over and over again) and the character set is very limited.
There was a 'programming cartridge' for the G7000 but was also severly limited by this lack of RAM and screen space and it had its own simulated instruction set, not related to the 8048.

Even the bigger brother G7400 did not have enough system RAM to run Basic directly, the external module Basic module which was available contains a Z80 with 16 kBytes RAM and Basic ROM. It also had a cassette interface for storing programs. The G7400 is then used as a 'terminal', the G7400 can display 40 characters by 25 lines with the extra graphics chips.
The Basic was a modified version of Micro$oft Basic.
 
Semi-related tangent: How much "better" is the MCS51 as compared to the MCS48 (or whatever it's called, the 8748/8048)?

If there is any chance of porting the software you all are writing/using in this thread over to the 8048 you might be able to finally after about 4½ decades have a decent basic for the Videopac G7000 / Magnavox Oddysey 2, with it's full alphanumeric membrane keyboard and whatnot.
I have its successor, the G7200. It had a BASIC module/cartridge but that had its own CPU. I did a quick search and it seems that Gert does know more of it.

@gertk : I do have the C7010 chess module with the NSC800 processor. If interested to have look at it, just let me know.

Back to the topic: could it be interesting to port all the 8048 software to the 8052? Next question: what about the graphics, add a video chip? I would not mind to end up with a small game computer based on the 8052 or more modern clone, using a modern (USB or PS/2) keyboard, etc. Just some wild thoughts three month before my retirement :)
 
Some years ago I delved into the Videopac systems, I still have a few of them. I made a protoype ROM emulator cartridge based on an ARM chip from NXP. It put the correct bits on the bus in realtime after being triggered by a an interrupt caused by the 8048 read access.
I have its successor, the G7200. It had a BASIC module/cartridge but that had its own CPU. I did a quick search and it seems that Gert does know more of it.

@gertk : I do have the C7010 chess module with the NSC800 processor. If interested to have look at it, just let me know.
Some years ago I delved into the Videopac systems. I have quite a few still. I did make a prototype ARM based cartridge which mimic-ed a ROM and same time later even the speech module, both in real time just by having the ARM CPU interrupted on the read access and delivering the proper data just in time. That was with a 100 MHz ARM chip from NXP.

The Chess module functions on both the standard Videopac and Videopac+ systems and it has the NSC800 which is internally like a Z80 but externally like a 805x or 8085 with a multiplexed address and data bus and such.

The Basic module works only on the Videopac+ series because it needs the 40x25 text mode to function and also the extended keyboard of the Videopac+
Back to the topic: could it be interesting to port all the 8048 software to the 8052? Next question: what about the graphics, add a video chip? I would not mind to end up with a small game computer based on the 8052 or more modern clone, using a modern (USB or PS/2) keyboard, etc. Just some wild thoughts three month before my retirement :)
I am using SPI LCD displays on the 8052 at the moment, but it needs higher SPI rates to really do games. One way is to add some hardware which handles the fast serial transfer and just needs a single parallel load to start. With a few TTL chips this is doable (counter, shift register and some glue logic). The shift clock can be the raw input clock of the 8052 for example. With this high clock frequencies you would not have to wait until the byte is sent as it is out before the CPU could test it again :-)
Some of these SPI LCD displays can handle over 100 MHz SPI clocks. Sizes range from 2 to 4 inches and resolutions vary from 320x240 to 480x320 in 16 or even 24 bit color.

On a stock 8052AH Basic @ 11.0592 MHz using software SPI, it takes a few seconds to just clear the screen on the 320x240 LCD (it needs 16 bits per pixel)

Speaking of software SPI: I found out the 805x has a simple instruction to set/reset a single bit on a port according the state of the carry bit. So you can do something like this:

Code:
; send a byte to the software SPI bus
spi_write:
        MOV     R1,#8   ; 8 bits to go
send_loop:
        RLC     A
        MOV        SPI_DAT,C
        SETB    SPI_CLK
        CLR     SPI_CLK
        DJNZ    R1,send_loop
        RET

I did look at the toggle instructions (CPL bit) but they have no advantage in speed over the SETB bit or CLR bit.
 
The G7000/Odyssey 2 is not capable of running Basic since there are only 128 bytes of RAM available, Also the videochip can not display a full screen of text without doing some major tricks (like multiplexing the 4 'quads' over and over again) and the character set is very limited.
There was a 'programming cartridge' for the G7000 but was also severly limited by this lack of RAM and screen space and it had its own simulated instruction set, not related to the 8048.

Even the bigger brother G7400 did not have enough system RAM to run Basic directly, the external module Basic module which was available contains a Z80 with 16 kBytes RAM and Basic ROM. It also had a cassette interface for storing programs. The G7400 is then used as a 'terminal', the G7400 can display 40 characters by 25 lines with the extra graphics chips.
The Basic was a modified version of Micro$oft Basic.
Oh, yes, the display would for sure be a limiting factor. But it's possible to have RAM in carts.

In particular I remember seeing a description for at DIY cartridge that has RAM, an EPROM and an UART (!!) and some logic, where the EPROM contains code to download a cart image to the SRAM chip and then switch in that chip as program memory, where all of this runs on the 8048 directly.
 
I am using SPI LCD displays on the 8052 at the moment,
I have done nothing with SPI so far and so I didn't think of this option. Do you have a manual like "Using SPI displays with a 8052 for dummies"? :)

At this moment I' more in the "gathering phase" than in the "doing phase". Due to work my room has become more like storage so I have to clean/organize it before I can use as a work room again.
 
I have done nothing with SPI so far and so I didn't think of this option. Do you have a manual like "Using SPI displays with a 8052 for dummies"? :)
Ha, not really no, but I get my initialisation parameters for such displays from the code examples and libraries in the Arduino IDE
It is not always easy to find out what controller is on the display but once known there are datasheets to be found.

I have some examples for the 320x240 displays already running on the 8052 doing simple stuff as putting a character on the screen at location X,Y and setting individual pixels with a specified color. I recently got an extra 480x320 display in, had one already but it had a touch screen which I did not need for testing on the 8052. Some of these displays also have a SD card slot (which also can be run with SPI).

2025-10-19 15.53.44.jpg2025-10-19 15.54.27.jpg2025-10-19 17.31.27.jpg2025-10-19 17.46.23.jpg2025-10-19 17.46.47.jpg
At this moment I' more in the "gathering phase" than in the "doing phase". Due to work my room has become more like storage so I have to clean/organize it before I can use as a work room again.
My work room turns also quite fast into a storage room even when in 'workroom' use. :-) Far too much interesting stuff to be thrown out easily.
 
Took me some days(!) to convert this simple Basic program to 8051 assembler...
Proved that 805x assembler eight bit signed numbers comparisons are really tricky to do.

Code:
10 rem bresenham test 
15 clg:dmode 12
20 for x=0 to 127 step 4
30 y1=0:y2=127
40 x1=x:x2=127-x
50 gosub 1000
60 next x
80 for y=0 to 127 step 4
90 x1=0:x2=127
100 y1=y:y2=127-y
110 gosub 1000
120 next y
999 end
1000 rem bresenham
1010 dx=abs(x2-x1):if x1<x2 then sx=1 else sx=-1
1020 dy=abs(y2-y1):if y1<y2 then sy=1 else sy=-1
1030 if dx>dy then err=dx/2 else err=-dy/2
1040 rem draw loop
1050 plot x1,y1
1060 if (x1=x2) .and. (y1=y2) then return
1070 e2=err
1080 if (e2 > -dx) then err=err-dy:x1=x1+sx
1090 if (e2 < dy) then err=err+dx:y1=y1+sy
1100 goto 1050

I ended up making the compare function into a separate subroutine.
Code:
;
; Bresenham line draw (arbitrary direction)
;    
draw_bresenham:
    ; Calculate ABS(DX) and SX 
    MOV     A, NEW_X    ; X2
    CLR        C            ; clear borrow flag!
    SUBB     A, X_COORD    ; X1
    
    ; if the sign bit has been set the answer is negative and we need to make it absolute
    JNB        ACC.7,draw_pos_dx    ; sign bit is 0 so skip
    CPL        A            ; negate A
    INC        A            ; make 2-complement
    MOV        DX,A        ; save in DX
    MOV        SX,#-1        ; SX is negative
    JMP        calc_dy

draw_pos_dx:
    MOV     DX, A        ; DX=ABS(X2-X1)
    MOV        SX,#1        ; SX is positive
    
calc_dy:
    ; Calculate ABS(DY) and SY
    MOV     A, NEW_Y    ; Y2
    CLR        C            ; clear borrow flag
    SUBB     A, Y_COORD    ; Y1
    
    JNB        ACC.7,draw_pos_dy
    CPL        A            ; negate A
    INC        A            ; make 2-complement
    MOV        DY,A        ; save in DY
    MOV        SY,#-1        ; SY is negative
    JMP        calc_done
    
draw_pos_dy:
    MOV     DY, A        ; DY=ABS(Y2-Y1)
    MOV        SY,#1        ; SY is positive

calc_done:
    
; setup initial ERR
; check if DX>DY
; 
    mov        A,DX
    mov        B,DY
    call    compare            ; do signed compare
    
    jz        err_neg            ; if DX=DY
    jnc        err_neg            ; if DX<DY

    ; else make ERR=DX/2
    mov        A,DX
    clr        C                ; divide by two
    rrc        A
    mov        ERR,A
    jmp        DRAW_LOOP

err_neg:
    ; make ERR=-DY/2
    mov        A,DY
    clr        C                ; divide by 2
    rrc        A

    cpl        A                ; negate A
    inc        A
    mov        ERR,A

DRAW_LOOP:
    call    plot        ; plot X_COORD,Y_COORD
    
    ; check if X1=X2 and Y1=Y2 and if so: return
    MOV        A,X_COORD
    CJNE    A,NEW_X,NOT_YET

    MOV        A,Y_COORD
    CJNE    A,NEW_Y,NOT_YET
    ; endpoint reached, so return
    RET
    
NOT_YET:
    ; copy E2 from ERR
    MOV    E2,ERR
    
    ; calculate -DX and store in B 
    MOV A, DX      ; Move the value of DX to the accumulator
    CPL A          ; Complement the accumulator (one's complement)
    INC A          ; Increment to get two's complement (-DX)
    ; Now A holds the value of -DX, move to B
    MOV    B,A            ; B = -DX
    
    ; check E2 > -DX
    MOV        A,E2
    CALL    compare            ; do the signed comparison 

    JZ        check_DY        ; if E2 = -DX 
    JNC        check_DY        ; if E2 < -DX
    
    ; else E2 > -DX 
    ; ERR=ERR-DY
    MOV        A,ERR
    CLR        C
    SUBB    A,DY
    MOV        ERR,A
    
    ; X1=X1+SX
    MOV        A,X_COORD
    ADD        A,SX
    MOV        X_COORD,A
    
check_DY:
        
    ; check E2<DY
    MOV        A,E2
    MOV        B,DY
    CALL    compare        ; do signed compare

    JZ        check_done    ; if E2 = DY
    JC        check_done    ; if E2 > DY
    
    ; ERR=ERR+DX
    MOV        A,ERR
    ADD        A,DX
    MOV        ERR,A
    
    ;Y1=Y1+SY
    MOV        A,Y_COORD
    ADD        A,SY
    MOV        Y_COORD,A

check_done:
    jmp        DRAW_LOOP    ; repeat loop

; signed compare A and B
; return with:
; ZF = 1 and A=0  if A = B
; C  = 1 and A=FF if A > B
; C  = 0 and A=FF if A < B
compare:
        CLR    C
        SUBB    A,B
        JZ        A_EQUAL

        ; check if ACC.7 and OV have different values
        ; if they are the same:  A>B
        ; if they are different: A<B
        
        ; check OV flag first
        JNB    OV,CHECK_SIGN_BIT    ; if not set (OV=0)
        
        JB    ACC.7,A_GREATER        ; if OV=1 and ACC.7=1
        JMP    A_LESS                ; OV=1 and ACC.7=0 
        
CHECK_SIGN_BIT:
        JB    ACC.7,A_LESS        ; if OV=0 and ACC.7=1
        JMP    A_GREATER            ; if OV=0 and ACC.7=0 
        
A_EQUAL:
        RET

A_GREATER:
        MOV        A,#0ffh            ; block zero test
        SETB    C
        RET

A_LESS:
        MOV        A,#0ffh            ; block zero test
        CLR        C
        RET

But now my LCD (128x128) DRAW function does all directions
:)
 
Great! From the 12th on I have some more time to dive into it so expect some more questions then.

Somewhere in the '80s (I think) Elektor/Elektuur published an article about an 8052-BASIC SBC in combination with a big LCD screen. Does that ring a bell? Otherwise I have to check all PDFs. Anyway, I have two of these screens. Could be interesting for you. In return: your knowledge that you share here anyway :)
 
Great! From the 12th on I have some more time to dive into it so expect some more questions then.

Somewhere in the '80s (I think) Elektor/Elektuur published an article about an 8052-BASIC SBC in combination with a big LCD screen. Does that ring a bell? Otherwise I have to check all PDFs. Anyway, I have two of these screens. Could be interesting for you. In return: your knowledge that you share here anyway :)
Would that be this article?
https://www.elektormagazine.nl/magazine/elektor-198804/45600

I had one of those LCD's many years ago, I kept it together with the controller chip (mounted with double sided tape onto veroboard). Alas when I took it out of the box some years ago, the LCD had gone bad (dark patches all around the sides of the screen) so I had to throw that away. Not sure if I kept the controller.
These LCD's need a constant flow of data and clock signals (heavily multiplexed) otherwise they will suffer from DC bias deterioration. The controller chip takes care of that but the overall circuit was quite complex with some RAM, ROM, latches/buffers as I recall.


I have made a start with getting the schematic for my 8 bit parallel bus to SPI interface into KiCad. With SMD chips and a small board that would need no more space than say a DIP40 IC.
That would work much faster than the bit-banging we have to do now, the bitrate could be derived from the CPU clock or a small onboard oscillator with a divider.

Just need to figure out which chips have to run on 3.3 Volts (since that is what most SPI devices these days use) and which have to run on (or be tolerant to) 5V for interfacing with the CPU.

The interface uses a single address line to differentiate between the SPI data (read/write) and the SPI control lines like command/data, reset and such. You would simply write a byte to the data-out register and it gets sent out at the selected bitrate, at the same time it will clock in the data (if any) from the SPI device and make it available in the data-in register. The control lines could be handled by a simple 4 or 8 bit latch.
 
Back
Top