Code Monkey home page Code Monkey logo

espple's Introduction

espple - Apple 1 Emulator with PAL RF Output

Try out the original Apple 1 with a 3$ ESP8266 board on your living room TV - wirelessly!

espple

Features

  • MOS 6502 CPU emulated at native speed (1 MHz)
  • 20 kB RAM
  • PAL TV signal output
  • Original Signetics 2513 ROM characters
  • Telnet used for keyboard input
  • Built-in TFTP server for uploading software
  • Everything is wireless

screenshot

How does it work?

High frequency modulated video signal is generated internally (via I2S/DMA) and all you need is a single piece of wire to play antenna. Even though it's extremely weak, it can still be picked up on your TV in the same room.

I2S stands for Inter-IC Sound, a standard for digital audio devices interconnect. ESP8266 supports I2S bus data output using DMA transfers, providing a way to generate a steady stream of bits while the processor can do something else. It gets interrupted when the 'bucket' is empty, and it fills it again with more bits to be pumped out.

By generating patterns in those bits, it's possible to produce a meaningful waveform which can be interpreted as a video signal by a TV. Since I live in Europe, the chosen video system is 625 lines CCIR system B (basically PAL B without the color).

spectrum


Instructions

Flashing the files

  1. Install programmer software.

    • Linux - install esptool (apt-get install esptool on debian-like systems, pip install esptool or git clone the repo),
    • Windows - use Flash download tools
  2. Write the binary files (adjust your port name)

esptool -p /dev/ttyUSB0 write_flash --flash_mode dio 0x00000 image.elf-0x00000.bin 0x40000 image.elf-0x40000.bin

Tip - ESP-12E modules require flash_mode dio, most other boards use qio.

  1. Provide your wi-fi credentials
make credentials ssid="Your SSID" password="Your password"

This will generate a .bin file containing the credentials and write it to flash memory at 0x3C000. Please keep this in mind and run this command again with dummy credentials if you intend to sell or borrow your ESP board.

  1. Connect a piece of breadboard jumper cable to the RX pin (GPIO 3)

  2. Turn your TV on and select analogue TV, PAL system - channel 4. Some manual fine tuning might be required.

  3. Telnet to the ESP - the IP address can be read through the cable used to flash the firmware. Make sure your terminal program is set to 115200,8N1. Press enter several times after connecting.

Loading the software

First you need to tell the built-in TFTP server where to store your program. To keep things simple, this always points to the last memory location examined using the built-in monitor which starts after a reboot (the one with the \ prompt).

For BASIC, the target address was E000 hex.

Simply type E000 and press enter, this will specify the upload target address. Then run the TFTP client on your computer and upload the binary file (adjust your target IP accordingly):

atftp -p -l software/basic-0xE000.bin 192.168.1.2

After TFTP client finishes, simply run the program from target location by typing the location followed by the letter R. If you just transferred BASIC, you would type E000R and be greeted with the '>' prompt.

Rebooting

Press Ctrl + C when connected through telnet to trigger emulator reboot. Neither wi-fi or telnet connection will be dropped.

Demo

Espple video demonstration

Click on the image to see a video of Espple running.

Help

Q. Backspace doesn't work - it shows _

A. This is by design, Apple 1 output works more like a teletype, there is no going back so this is the "rub out" symbol which tells the computer to disregard the previous symbol.

Q. I've flashed your bin files and now I'm in a reboot loop

A. My board is an ESP-12E, and requires DIO flash mode to be set (2 pins used for address and data) as opposed to QIO mode (4 pins used) some other variants use. Try flashing with DIO and see if that helps.

Q. Wifi doesn't connect

A. Make sure you've set the credentials like instructed. Try moving the ESP board closer to the access point and configure it to use one of the lower frequency channels (1-6). You can monitor progress using a serial connection (115200, 8N1).

Q. Why can't I simply use the serial as a keyboard input? This wi-fi thing seems overengineered.

A. Because the UART0 RX line is already being used as an I2S output, and UART1 exposes TX pin only to the board.

On the plus side, it's totally wireless.

Q. Program doesn't start after TFTP upload

A. A packet was probably lost, try again and make sure you have a good wi-fi reception.

Q. I'd like to use NTSC

A. Few people asked about the possibility of generating NTSC signal so I've updated the source to support both. Edit generate_video.c and change #define PAL to #define NTSC.

Q. I can't find a signal on the TV

A. Your RF input connector and the whole signal path is shielded inside the TV so there should be some sort of antenna plugged in. If you don't have an indoor antenna, a piece of wire will do just fine. Make sure you don't short the tip and ring of your input connector because you won't receive anything. In your TV menu choose analogue TV, choose PAL standard and select channel 4. The esp board emits at 60 MHz which is slightly lower than channel 4 frequency, so you might have to fine tune a bit. Most modern TVs should be able to automatically scan and find the channel for you.

Missing features

The emulator should accomodate for the terminal output delay. It should be possible to upload the original tape audio waveform over tftp and use the original Apple Cassette Interface to read it.

License

This software is licensed under the MIT license.

Credits

Video generation is derived from the much more impressive channel3 project by Charles Lohr.

CPU core is made using the fake6502 project by Mike Chambers.

Apple 1 was famously made by Stephen Wozniak, one of the greatest engineers of our time.

espple's People

Contributors

hrvach avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

espple's Issues

Compile Error - TypeError: a bytes-like object is required, not 'str'

Hello,
I tryed to build the wifi_credentials.bin but did not work, got only 0 byte file

$ make credentials ssid="MyWLAN" password="MyPassword"
python -c "open('wifi_credentials.bin', 'wb').write(''.join(i.ljust(32, '\0') for i in ['MyWLAN','MyPassword']))"
Traceback (most recent call last):
File "", line 1, in
TypeError: a bytes-like object is required, not 'str'
make: *** [Makefile:44: credentials] Fehler 1

Python 2.7.14
Python 3.6.4

How to fix this ?
Thanks

"demo mode" with software preloaded possible?

not knowing enough about the situation I'm not sure if there's room in your image, but is it possible to prep an image that will tape-load or somehow go into a "demo mode" without having to push images from TFTP? this would be useful in showing off the espple next to a "real" (or replica) apple 1 in a museum setting, for example. perhaps we can chat about what that would look like first, but having a bunch of things to load on the ESP would definitely improve the "time-to-interaction" for people checking it out. =] let me know what you think!

Flash memory address for Credentials and flash mode for NodeMCU

Great Project.

In README.md , Flash memory address to write file 'wifi_credentials.bin' is 0x3FC00.
But in Makefile , the address mentioned to write credentials is 0x3c000.
Which is the correct address ?

I have NodeMCU ESP8266 board. Which flash_mode should I use dio or qio ?

Thanks.

DHCP won't work!

Log:
`
add if0
f 0, scandone
state: 0 -> 2 (b0)
state: 2 -> 3 (0)
state: 3 -> 5 (10)
add 0
add 1
pm open phy_2,type:2 0 0
cnt

connected with FRITZBoxKarin, channel 11
dhcp client start...`
and here it ends!
No more Output!
Not listet in Router Interface!!

I'm trying to replace the font, could you please explain the structure of signetics_video_rom.h

I'm trying to replace the font but I am having trouble working out how to convert a bitmap font such as:

https://github.com/idispatch/raster-fonts/blob/master/06x08_Terminal_Microsoft.png

into the format used in this file:

https://github.com/hrvach/espple/blob/master/user/signetics_video_rom.h

Am I right in understanding that somehow each pixels is replicated three times in the above file? That's what I thought but I looked for such a pattern in the data and could not find it.

Would you mind please suggesting an approach for converting a bitmap font into the required format, or explaining more about this format?

thanks!

How can I adjust the overscan left and right?

On one of my televisions the image runs over the right and left edges of the screen.

Can you suggest what settings I would need to adjust to squash it in so it's not running off the right and left edge?

thanks!

build with NONOS-SDK-V2.0.0

Hi - great project - well impressed with the make credentials.
I am having problems with the telnet logging out after 20-30secs, and I have not yet got the TV to see the signal, but to help understand what is going on I have tried to rebuild the code with some debug.
And that is where I hit problems, I am using ESP8266_NONOS_SDK-V2.0.0.0 _16_08_10 for another project so I have tried tat bhut get error:
"region `iram1_0_seg' overflowed by 2536 bytes"
I believe this is related to the ICACHE_FLASH_ATTR directive, can you advise?

Thanks.

Not succeeding in getting this to build.

Hello,

I'm trying to piece together steps to build this - unless I have missed them, there doesn't seem to be an explanation of what build config/libraries are needed to build this so I'm just trying to do what I can.

I'm using the ESP8266_NONOS_SDK - is that what I am meant to be using? The messages on the repo seem to be saying that SDK is being phased out ("It is suggested that the ESP8266_RTOS_SDK, instead of ESP8266 NonOS SDK, be used for your projects") https://github.com/espressif/ESP8266_NONOS_SDK

Any help welcome.

Even better - if you wouldn't mind doing a build using all the latest SDK's and perhaps posting the steps it would be a huge help.

I'm stuck at this point:

(venv3.9) foo@foo-Mini espple % make
/Users/foo/esp/xtensa-lx106-elf/bin/xtensa-lx106-elf-gcc -mlongcalls -I/Users/foo/esp/ESP8266_NONOS_SDK/include -Iinclude -O3 -I/Users/foo/esp/ESP8266_NONOS_SDK/include/ -DICACHE_FLASH  user/fake6502.c user/generate_video.c user/user_main.c  -nostdlib -Wl,--start-group -lmain -lnet80211 -lcrypto -lssl -lwpa -llwip -lpp -lphy -Wl,--end-group -lgcc -T/Users/foo/esp/ESP8266_NONOS_SDK/ld/eagle.app.v6.ld -B/Users/foo/esp/ESP8266_NONOS_SDK/lib -o image.elf
user/generate_video.c: In function 'testi2s_init':
user/generate_video.c:263:38: warning: passing argument 2 of 'ets_isr_attach' from incompatible pointer type [-Wincompatible-pointer-types]
         ets_isr_attach(ETS_SLC_INUM, slc_isr);
                                      ^~~~~~~
In file included from /Users/foo/esp/ESP8266_NONOS_SDK/include/os_type.h:28,
                 from /Users/foo/esp/ESP8266_NONOS_SDK/include/user_interface.h:28,
                 from user/generate_video.c:9:
/Users/foo/esp/ESP8266_NONOS_SDK/include/ets_sys.h:67:38: note: expected 'ets_isr_t' {aka 'void (*)(void *)'} but argument is of type 'void (*)(void)'
 void ets_isr_attach(int i, ets_isr_t func, void *arg);
                            ~~~~~~~~~~^~~~
user/generate_video.c:263:9: error: too few arguments to function 'ets_isr_attach'
         ets_isr_attach(ETS_SLC_INUM, slc_isr);
         ^~~~~~~~~~~~~~
In file included from /Users/foo/esp/ESP8266_NONOS_SDK/include/os_type.h:28,
                 from /Users/foo/esp/ESP8266_NONOS_SDK/include/user_interface.h:28,
                 from user/generate_video.c:9:
/Users/foo/esp/ESP8266_NONOS_SDK/include/ets_sys.h:67:6: note: declared here
 void ets_isr_attach(int i, ets_isr_t func, void *arg);
      ^~~~~~~~~~~~~~
In file included from user/generate_video.c:12:
include/dmastuff.h:11:71: warning: implicit declaration of function 'rom_i2c_writeReg_Mask'; did you mean 'i2c_writeReg_Mask'? [-Wimplicit-function-declaration]
 #define i2c_writeReg_Mask(block, host_id, reg_add, Msb, Lsb, indata)  rom_i2c_writeReg_Mask(block, host_id, reg_add, Msb, Lsb, indata)
                                                                       ^~~~~~~~~~~~~~~~~~~~~
include/dmastuff.h:14:7: note: in expansion of macro 'i2c_writeReg_Mask'
       i2c_writeReg_Mask(block, block##_hostid,  reg_add,  reg_add##_msb,  reg_add##_lsb,  indata)
       ^~~~~~~~~~~~~~~~~
user/generate_video.c:279:9: note: in expansion of macro 'i2c_writeReg_Mask_def'
         i2c_writeReg_Mask_def(i2c_bbpll, i2c_bbpll_en_audio_clock_out, 1);
         ^~~~~~~~~~~~~~~~~~~~~
user/user_main.c: In function 'reset_emulator':
user/user_main.c:54:9: warning: implicit declaration of function 'reset6502' [-Wimplicit-function-declaration]
         reset6502();
         ^~~~~~~~~
user/user_main.c: In function 'emulator_task':
user/user_main.c:154:9: warning: implicit declaration of function 'exec6502'; did you mean 'read6502'? [-Wimplicit-function-declaration]
         exec6502(INSTRUCTIONS_CHUNK);
         ^~~~~~~~
         read6502
user/user_main.c: In function 'user_init':
user/user_main.c:241:20: warning: passing argument 1 of 'ets_strcpy' from incompatible pointer type [-Wincompatible-pointer-types]
         ets_strcpy(&stationConf.ssid, &credentials[0]);
                    ^~~~~~~~~~~~~~~~~
In file included from user/user_main.c:5:
/Users/foo/esp/ESP8266_NONOS_SDK/include/osapi.h:46:7: note: expected 'char *' but argument is of type 'uint8 (*)[32]' {aka 'unsigned char (*)[32]'}
 char *ets_strcpy(char *s1, const char *s2);
       ^~~~~~~~~~
user/user_main.c:241:39: warning: passing argument 2 of 'ets_strcpy' from incompatible pointer type [-Wincompatible-pointer-types]
         ets_strcpy(&stationConf.ssid, &credentials[0]);
                                       ^~~~~~~~~~~~~~~
In file included from user/user_main.c:5:
/Users/foo/esp/ESP8266_NONOS_SDK/include/osapi.h:46:7: note: expected 'const char *' but argument is of type 'uint32 *' {aka 'unsigned int *'}
 char *ets_strcpy(char *s1, const char *s2);
       ^~~~~~~~~~
user/user_main.c:242:20: warning: passing argument 1 of 'ets_strcpy' from incompatible pointer type [-Wincompatible-pointer-types]
         ets_strcpy(&stationConf.password, &credentials[8]);
                    ^~~~~~~~~~~~~~~~~~~~~
In file included from user/user_main.c:5:
/Users/foo/esp/ESP8266_NONOS_SDK/include/osapi.h:46:7: note: expected 'char *' but argument is of type 'uint8 (*)[64]' {aka 'unsigned char (*)[64]'}
 char *ets_strcpy(char *s1, const char *s2);
       ^~~~~~~~~~
user/user_main.c:242:43: warning: passing argument 2 of 'ets_strcpy' from incompatible pointer type [-Wincompatible-pointer-types]
         ets_strcpy(&stationConf.password, &credentials[8]);
                                           ^~~~~~~~~~~~~~~
In file included from user/user_main.c:5:
/Users/foo/esp/ESP8266_NONOS_SDK/include/osapi.h:46:7: note: expected 'const char *' but argument is of type 'uint32 *' {aka 'unsigned int *'}
 char *ets_strcpy(char *s1, const char *s2);
       ^~~~~~~~~~
user/user_main.c:247:9: warning: implicit declaration of function 'testi2s_init'; did you mean 'user_init'? [-Wimplicit-function-declaration]
         testi2s_init();
         ^~~~~~~~~~~~
         user_init
user/user_main.c:252:24: warning: passing argument 1 of 'ets_timer_setfn' discards 'volatile' qualifier from pointer target type [-Wdiscarded-qualifiers]
         os_timer_setfn(&emulator_callback_timer, (os_timer_func_t *) emulator_task, NULL);
                        ^~~~~~~~~~~~~~~~~~~~~~~~
In file included from user/user_main.c:5:
/Users/foo/esp/ESP8266_NONOS_SDK/include/osapi.h:67:34: note: expected 'ETSTimer *' {aka 'struct _ETSTIMER_ *'} but argument is of type 'volatile ETSTimer *' {aka 'volatile struct _ETSTIMER_ *'}
 void ets_timer_setfn(os_timer_t *ptimer, os_timer_func_t *pfunction, void *parg);
user/user_main.c:253:22: warning: passing argument 1 of 'ets_timer_arm_new' discards 'volatile' qualifier from pointer target type [-Wdiscarded-qualifiers]
         os_timer_arm(&emulator_callback_timer, 10, 1);
                      ^~~~~~~~~~~~~~~~~~~~~~~~
/Users/foo/esp/ESP8266_NONOS_SDK/include/osapi.h:72:49: note: in definition of macro 'os_timer_arm'
 #define os_timer_arm(a, b, c) ets_timer_arm_new(a, b, c, 1)
                                                 ^
/Users/foo/esp/ESP8266_NONOS_SDK/include/osapi.h:65:36: note: expected 'ETSTimer *' {aka 'struct _ETSTIMER_ *'} but argument is of type 'volatile ETSTimer *' {aka 'volatile struct _ETSTIMER_ *'}
 void ets_timer_arm_new(os_timer_t *ptimer, uint32_t time, bool repeat_flag, bool ms_flag);
user/user_main.c:256:24: warning: passing argument 1 of 'ets_timer_setfn' discards 'volatile' qualifier from pointer target type [-Wdiscarded-qualifiers]
         os_timer_setfn(&cursor_timer, (os_timer_func_t *) toggle_cursor, NULL);
                        ^~~~~~~~~~~~~
In file included from user/user_main.c:5:
/Users/foo/esp/ESP8266_NONOS_SDK/include/osapi.h:67:34: note: expected 'ETSTimer *' {aka 'struct _ETSTIMER_ *'} but argument is of type 'volatile ETSTimer *' {aka 'volatile struct _ETSTIMER_ *'}
 void ets_timer_setfn(os_timer_t *ptimer, os_timer_func_t *pfunction, void *parg);
user/user_main.c:257:22: warning: passing argument 1 of 'ets_timer_arm_new' discards 'volatile' qualifier from pointer target type [-Wdiscarded-qualifiers]
         os_timer_arm(&cursor_timer, 300, 1);
                      ^~~~~~~~~~~~~
/Users/foo/esp/ESP8266_NONOS_SDK/include/osapi.h:72:49: note: in definition of macro 'os_timer_arm'
 #define os_timer_arm(a, b, c) ets_timer_arm_new(a, b, c, 1)
                                                 ^
/Users/foo/esp/ESP8266_NONOS_SDK/include/osapi.h:65:36: note: expected 'ETSTimer *' {aka 'struct _ETSTIMER_ *'} but argument is of type 'volatile ETSTimer *' {aka 'volatile struct _ETSTIMER_ *'}
 void ets_timer_arm_new(os_timer_t *ptimer, uint32_t time, bool repeat_flag, bool ms_flag);
make: *** [image.elf] Error 1
(venv3.9) foo@foo-Mini espple %

thanks!

WiFi connect not working; continuous state: 0 -> 2 (b0) and reconnect

Hi,

I would likt to test your precompiled images on my "Wemos D1 mini". Flashing the 2 images and the one with the credentials work fine and Wemos boots. Serial console shows log @ 115200 baud but it seems that connecting to the WiFi access point (Fritz Box 7390; WPA/WPA2) does not work.
Access point is near and SSID is found. Channel = 1
Password has been provided correctly. I tried many variations of SSID and PW, also very simple with only normal and few characters. I also tried to change AP mode from WPA(TKIP) to WPA/WPA2 to WPA2(CCMP).

Do you have any suggestion?

Thanks in advance
Eva

My usual code to connect to WiFi is like this. Your code seem to behave differently...
WiFi.mode(WIFI_STA);
// IPAddress gateway(192, 168, 0, xx); // set gateway to match your network
// Serial.print(F("Setting static ip to : "));
// Serial.println(ip);
// IPAddress subnet(255, 255, 255, 0); // set subnet mask to match your network
// WiFi.config(ip, gateway, subnet);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(1000);
}
ip = WiFi.localIP();

Log:
f 0, scandone
state: 0 -> 2 (b0)
state: 2 -> 3 (0)
reconnect
state: 3 -> 0 (0)
f 0, scandone
state: 0 -> 2 (b0)
state: 2 -> 3 (0)
reconnect
state: 3 -> 0 (0)
f 0, scandone
state: 0 -> 2 (b0)
state: 2 -> 3 (0)
reconnect
state: 3 -> 0 (0)
f 0, scandone
state: 0 -> 2 (b0)
state: 2 -> 3 (0)
reconnect
state: 3 -> 0 (0)
f 0, scandone
state: 0 -> 2 (b0)
state: 2 -> 3 (0)
state: 3 -> 2 (2a0)
reconnect
state: 2 -> 0 (0)
f 0, scandone
state: 0 -> 2 (b0)
state: 2 -> 3 (0)
state: 3 -> 2 (2a0)
reconnect
state: 2 -> 0 (0)
f 0, scandone
state: 0 -> 2 (b0)
state: 2 -> 3 (0)
state: 3 -> 2 (2a0)
reconnect

8285 compatibility

This does not work with 8285 modules that have 1MB flash integrated and require DOUT.
Changing Flashing mode to DOUT alone doesn't help. Any idea how to recompile the code for 8285 compatibility?

binary with NTSC as the default?

Sorry if this isn't a terribly appropriate place to do this:

I appreciate the option for NTSC output, but is there any possibility we can get a binary with NTSC as the default video output, for people that don't have the ESP toolchain or are having trouble getting the environment set up?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.