I want to connect an Arduino or similar to my CPC in order to let the CPC interact with the outside world. I've had Z80-computers since the early 80's (Sharp MZ and MSX) but I've never worked with the Z80 at this level before.
I found this interesting MSX project: Coding Laboratory: Virtual MSX disk drive (http://codinglab.blogspot.no/2013/01/virtual-msx-disk-drive.html)
Basically it has a simple address decoder that pulls the WAIT/READY line low to force the Z80 to wait until the microcontroller has either read the databus or written to it. Then the microcontroller release WAIT/READY and the Z80 continues.
This looks rather easy, but can the same concept be used on the CPC?
As long as you don't hold the wait signal low for too long it should be fine.
Bryce.
So how long would "too long" be?
Take a look at the CPC Booster+ - That's an ATMEGA connected to the CPC Bus. CPC Booster - CPCWiki (http://www.cpcwiki.eu/index.php/CPC_Booster)
I already asked this.
to have such stuff woud need :
=cabling properly the Arduino to CPC.
=have some library on both the arduino and CPC to have them do stuff together.
good point with arduino :
you can get the ethernet shield and its micro-SD card plug used as ethernet/internet, or mass data storage...
with such a shield, you may emulate an HDD or Floppy dfisk or even ROMs perhaps, or get online.
the arduino could also be used to perform some additional tasks or functions I guess, like arithmetic functions or whatever...
yeah the ethernet shield doesn't allows to use both the SD card or the ethernet at the same time, not a big deal...
Really I don't understand why no coder-hobbyist did stuff like that.
Anyway, would be cool if TotO could create the cable to plug an Arduino Mega a theses models have a lot of I/O so you may put both an ethernet shield and the CPC) into his MotherX4... had to be the perfect combo and the way to properly use the 4th slot.
lemme check :
MotherX4 : done.
=plAY-CiTy : soon.
=X-MEM : done.
=Booster : done
=empty slot for Arduino then... :P
Quote from: Nilquader on 12:00, 11 July 14
Take a look at the CPC Booster+ - That's an ATMEGA connected to the CPC Bus. CPC Booster - CPCWiki (http://www.cpcwiki.eu/index.php/CPC_Booster)
Thank you! Very useful. I just took a look at the schematics and it looks like I only need to implement a subset of the CPCBooster to do exactly what I need :)
You could link the CPC to a RPi.
Quote from: joska on 11:47, 11 July 14
So how long would "too long" be?
The RAM isn't being refreshed while the /WAIT signal is held low, so more than a couple of milliseconds will cause the RAM to become corrupted or deleted completely.
@Steve: Yeah sure.
Bryce.
QuoteYou could link the CPC to a RPi.
yeah, the CPC being some sort of fancy terminal : big Video Display, soundcard and control/keyboard card...
:laugh:
QuoteSo how long would "too long" be?
this would be something like 33 bit or even more...65.537 would be enough to be "too long".
;)
I saw a blog where someone had connected one to a C64 if I find the post again I will provide a link here.
There is no difference (conceptually) between connecting a CPC to an RPi and connecting a PC to a server.
Quote from: MacDeath on 12:21, 11 July 14
I already asked this.
to have such stuff woud need :
=cabling properly the Arduino to CPC.
Basically you need two TTL logic chips to create the address decoder and a 74245 to buffer the databus.
Quote from: MacDeath on 12:21, 11 July 14
good point with arduino :
you can get the ethernet shield and its micro-SD card plug used as ethernet/internet, or mass data storage...
It would be very easy to use the Arduino/whatever to interface with an SD-card, giving the CPC either direct access to individual SD card sectors or even file system access (FAT driver on the Arduino). However, that would require a custom DOS on the CPC, which if far beyond my capabilities.
Quote from: MacDeath on 12:21, 11 July 14
with such a shield, you may emulate an HDD or Floppy dfisk or even ROMs perhaps, or get online.
Depending on the microcontroller I guess it would be rather straightforward to emulate the FDC. But I don't think it would be very practical to emulate a ROM-card.
Quote from: MacDeath on 12:21, 11 July 14
yeah the ethernet shield doesn't allows to use both the SD card or the ethernet at the same time, not a big deal...
I don't see the problem at all. True, both SD-cards and the various ethernet-modules use the SPI-interface, but the SPI-bus can be shared.
Anyway, my goal is not to create some sort of super-expansion for the CPC. I just want to learn something new. I might create a Symbiface compatible mouse (which would be useful to me), but I might also end up with nothing usable at all.
QuoteHowever, that would require a custom DOS on the CPC, which if far beyond my capabilities.
pretty sure FutureOS could handle that... :D
Quote from: steve on 12:35, 11 July 14You could link the CPC to a RPi.
I could, but that would be overkill for my needs. Also, it would cost 10 times as much as a simple Arduino-clone. Btw. what would you use the RPi for?
Quote from: Bryce on 12:38, 11 July 14
The RAM isn't being refreshed while the /WAIT signal is held low, so more than a couple of milliseconds will cause the RAM to become corrupted or deleted completely.
I see. A simple ATmega 328 would perform 16000 instructions in 1ms at 16MHz, so I don't think that would be a problem.
Quote from: joska on 12:52, 11 July 14
I could, but that would be overkill for my needs. Also, it would cost 10 times as much as a simple Arduino-clone. Btw. what would you use the RPi for?
Fileserver, internet connection, attach a camera and convert the pictures to some format that could be used as graphics in your programs.
I'm having a go at implementing something similar to this for my first hardware project :o
So I have managed to implement the address decoder, which after consulting this page (http://www.cpcwiki.eu/index.php/I/O_Port_Summary) to check for a free port, is working on port F300 and is implemented using NANDs and ORs as per the diagram attached.
I have a program running on the Arduino which will read the value at /G on the 74245 and if its low, it'll print out the byte on the data bus. The weird thing is that if I send an OUT &F300, 1, I dont see any output - but if I run a loop sending the same value, I see a lot of 0x80 (not 1??) values received. I'm assuming it might be something to do with timing, and more specifically maybe I need to hold the WAIT/READY low while I read from it. I tried connecting an Arduino pin to WAIT/READY, defaulted to HIGH, so i can pull it low when needed, but it just crashes the CPC - I'm assuming because it should not be constantly HIGH. The OP pointed to a tutorial written for an MSX where the guy ANDs his /G and his Arduino WaitEnable pin, but I'm struggling to follow the logic there. If anyone has any help on what is going on there that would me much appreciated!
I assume you are using an interrupt to react to /G? Anything else might be too slow (depending on the clock speed of µP).
Bryce.
Ah! Thanks Bryce. No actually I'm just doing a digital read in a tight loop - I'll check out how to implement an interrupt. Its an ATMEGA328 which I think is running at 20Mhz.
The concern in the back of my mind is even if I react to /G very quickly, by the time I have read the D0-D7 pins they could have changed - so presumably that is the purpose of the WAIT/READY signal?
If D0 to D7 are all connected to the same port of the 328 you can read them with a single command immediately within the interrupt. /G should be connected to a different pin of the AVR and used to trigger the interrupt. At 20Mhz that shouldn't be an issue.
Bryce.
Brilliant, I'm getting there thanks! - I've implemented it as an interrupt and now its responding every time, not only when I put it in a loop to bombard it with data!
Yes I remember reading you can read them as a single byte using PINB, ill try that next! The only problem I can think of is that interrupts only work on pins 2 and 3 which are part of the large 8 pin port I'd need to use to read a byte in one go. I'll try and come up with a solution
CheersNic
The 328 also has pin-change interrupts on each pin, so you're not restricted to just the INT0/1 pins.
Thanks pelrun, I got the pin change interrupt working, only as it's pin change it gets fired twice going low then going back high. Also still not getting the correct data off the data bus! Will keep on persevering though...
OK, got it working finally!
What I did was basically the same as the first example in this thread - I connected G to an OR gate along with a signal from the Arduino I called FORCE_READY (maybe it should be called FORBID_WAIT or something). FORCE_READY sits low normally so the only thing keeping /WAIT high is G. As soon as G drops low, it pulls /WAIT low with it to give me time to read the bus, then once I have the data I set FORCE_READY high which makes /WAIT go high, the Z80 will move to next instruction so /G will be HIGH again, which I wait for, then set FORCE_READY low to wait for the next interrupt.
Next steps will be to figure out how to send data, but I can see there are a few clues in the first example again :)
Thanks for all the help and pointers!
Nic
I managed to get sending from device to the CPC working, I was not too difficult in the end, just needed to add an AND gate to handle either /WR or /RD going low then as described by Raul use the /RD signal to control the 74245's DIR pin.
One weird think I have noticed, and could do with some clarification on, is that when I plug in my DDI5, the data received is incorrect. I'm sending 255, but the CPC is getting 223 - seems bit 5 on the data bus is being held low for some reason. Removing the DDI5 fixes the problem, so guessing that the IO address I'm using (0xF100) has some conflict with it.
I went over to the IO Port Summary page (https://www.cpcwiki.eu/index.php/I/O_Port_Summary) again to check, but the DDI5 isn't listed, so I figure that the addresses for the 765 FDC which presumably it is emulating will be the same or at least compatible. My main question is around the Decoded As column on this page - if I'm understanding this correctly, it only actually looks at 4 bits in the address bus here to determine the address - seems like that is a lot of potential for conflict? E.G to find I/O requests to #FB7E, it ignores the majority of the bits and only checks 0,7,8 and 10 %xxxxx0x1 0xxxxxx0 is that right? Could that be why I'm seeing issues - my address F100 in binary is %11110001 00000000 so it would actually match that pattern. The reason I'm questioning it is because I'm sure I must have misunderstood something here because surely that would conflict with loads of devices?
Yup, partial decoding is the norm rather than the exception as far as CPC internal devices go. While most addresses in the 16-bit IO space are conflicted due to the partial decoding, there is always at least one address for each device that unambiguously addresses it. So it's the responsibility of the code to avoid the ambigious ones. Basically that means putting 1's in every don't care bit position, which (unsurprisingly) results in the "standard" address for that device.
To find a free address for a new peripheral, it's necessary to start from an IO address with all 5 highest bits set (i.e. 0b11111xxx xxxxxxxx or ANDed with 0xF800). All the standard internal devices have at least one of those five bits set to 0. After that it's just a matter of picking an address that doesn't collide with an existing peripheral, which is still pretty easy if you're doing full decoding and only after a couple of addresses.
Ah, I see, thanks for the explanation! It makes more sense now why everything seems to be towards the end of the address space. I suppose it was because it was cheaper back in 1984 to only partially decode the internal devices, fewer logic chips needed?
Yup, that's it. The more bits you decode, the more logic you need, which increases chip count, board size and assembly costs. In fact the "inverted one-hot" method that's being used means the decoding is practically free, as you can just run a single address line direct to the chip-select pin of the appropriate IC.
Also the Z80 was intended to only have an 8-bit IO address space; it's technically an undocumented quirk of the implementation that puts B into the high byte of the address bus during an IO cycle. So abusing the high byte to allow simple addressing of the internal devices didn't only allow the CPC to reduce costs, it still left a bigger IO space for peripherals compared to other z80 based systems that only used it as documented!
Interesting! I presume that is also why we only use OUT (C) instead of OUT (BC)
Bingo! I almost mentioned that but didn't quite get around to it :D
Thread cleaned. Happy new year everyone, didn't you hear? 😀
[EDIT]VintageAdvantage is under moderation for being abusive. The reason in the HoS.
Quote from: nicf82 on 20:54, 25 December 20
OK, got it working finally!
Would you consider writing up what exactly you did? I would be super interested in how that works and how the circuit looks like.
Sure I can do, I'm just learning this stuff myself thought so I'm sure there will be some mistakes in there! I'm just trying to fix a problem which stops the CPC powering up when the Arduino is externally powered which I think is caused by a ground loop. Ill post what I did after that.
Make sure your circuit isn't inadvertently holding /WAIT if it's powered up before the CPC is... :D
Yeah I did think that, but don't think it could be really it needs the correct address etc to be decoded to pull that pin low. Also when I disconnect the Arduino GND it works, and continues to work if I plug it back in, after powering on the CPC. When the CPC monitor is on without the computer, and the Arduino ground is plugged in I head and see interference on the screen, so that's why I'm thinking ground loop?
First draft of a guide to setting this up: https://gist.github.com/nicf82/18eced4ebf9648cb47963bdf6f21a345 - I'm 100% confident there will be some mistakes in there but if anyone tries it and spots any or if anything isn't clear please let me know!
Don't assume that logic behaves sensibly while the system is initially powering up - everything is still an analog device at the lowest level and until the voltage settles things will be chaotic. That includes the logic on your breadboard, which looks like you're still powering from the CPC in the diagram.
If you watch the /RESET pin you can detect when the CPC is held in reset during initial power on, Keeping out of the way during this period is a good strategy even if it's not the root cause of this particular bug.
A ground loop is certainly possible though - what happens if you power the arduino from a battery pack instead?
Quote from: pelrun on 02:46, 03 January 21Don't assume that logic behaves sensibly while the system is initially powering up - everything is still an analog device at the lowest level and until the voltage settles things will be chaotic. That includes the logic on your breadboard, which looks like you're still powering from the CPC in the diagram.
If you watch the /RESET pin you can detect when the CPC is held in reset during initial power on, Keeping out of the way during this period is a good strategy even if it's not the root cause of this particular bug.
I think I would need to introduce a tri-state buffer for this - so I can keep it in high impedance for a short time on startup until I'm ready to hold it low or high - to be honest I don't quite understand how this works at all right now when I'm outputting HIGH from on the /WAIT - what if some other device wanted to pull it LOW. Will do a bit of experimenting.
I haven't tried with a battery, but I'll give it a go!
Cheers!
Nic
Quote from: nicf82 on 21:26, 02 January 21
Yeah I did think that, but don't think it could be really it needs the correct address etc to be decoded to pull that pin low. Also when I disconnect the Arduino GND it works, and continues to work if I plug it back in, after powering on the CPC. When the CPC monitor is on without the computer, and the Arduino ground is plugged in I head and see interference on the screen, so that's why I'm thinking ground loop?
How are you powering the Arduino? Through USB or the barrel socket? I would definitely add an external pull-up to the /WAIT signal to ensure it's physically being pulled high while the AVR ports are being initialised.
Bryce.
I'm using USB, OK will give this a try also!
Quote from: nicf82 on 11:20, 03 January 21
I think I would need to introduce a tri-state buffer for this - so I can keep it in high impedance for a short time on startup until I'm ready to hold it low or high - to be honest I don't quite understand how this works at all right now when I'm outputting HIGH from on the /WAIT - what if some other device wanted to pull it LOW. Will do a bit of experimenting.
You've got a couple of options; either a series resistor or a series diode. The series resistor is what the gate array uses to drive /WAIT with; if nothing else is driving the line it looks normal, but when something else is trying to drive it the opposite way it limits the current that can flow to a safe level. The diode essentially makes your output look like an open-drain, where you can only drive low levels, not high.
A pullup probably isn't necessary, as the z80 should be doing that already.
You could use an open collector setup to create a tri-state output.
Bryce.
Thanks pelrun, yes the diode makes sense, so unless I'm pulling LOW, it'll not allow any current to flow. Ill do a bit of digging into an open collector setup Bryce sounds interesting, all good learning for me.
Cheers!
Nic
Quote from: Gryzor on 17:29, 01 January 21
Thread cleaned. Happy new year everyone, didn't you hear? 😀
[EDIT]VintageAdvantage is under moderation for being abusive. The reason in the HoS.
He is right about the 16 Bit I/O of the Z80. the OUT (C),r instructions are a reality.
Of course lots of companies used 8 bit I/O, but also lots of companies used the 8088 instead the 8086 for exactly the same reason.
In CPCs world we need to use 16 bit I/O! Else ist won't work.
Why delete his post? Why not Pelruns post?
Please don't start this again - or do it in the HoS thread :laugh:
Quote from: pelrun on 07:03, 31 December 20
Yup, partial decoding is the norm rather than the exception as far as CPC internal devices go. While most addresses in the 16-bit IO space are conflicted due to the partial decoding, there is always at least one address for each device that unambiguously addresses it. So it's the responsibility of the code to avoid the ambigious ones. Basically that means putting 1's in every don't care bit position, which (unsurprisingly) results in the "standard" address for that device.
To find a free address for a new peripheral, it's necessary to start from an IO address with all 5 highest bits set (i.e. 0b11111xxx xxxxxxxx or ANDed with 0xF800). All the standard internal devices have at least one of those five bits set to 0. After that it's just a matter of picking an address that doesn't collide with an existing peripheral, which is still pretty easy if you're doing full decoding and only after a couple of addresses.
IMHO that's made too easy for hardware creators. Yes, the way you describe it will work as long as the CPC uses exactly one expansion. Or in few cases maybe with two expansions as long as their I/O addresses are very different.
However, IMHO, good practice is to decode as much as possible of the I/O address. Because only this will enable the user to use different hardware expansions at the same time.
The best practice is of course to decode full 16 bit I/O, only in this case you're on the safe side.
Sadly in CPC world there are lots of examples of incompatible hardware, because the producers only decode a bunch of I/O address bits, but not enough.
This is my personal perspective, the one of somebody who uses multiple expansions at once. And also the perspective of probably most / all good programmers. Of course few guys will look at this topic in a different way.
Quote from: nicf82 on 09:58, 04 January 21
Thanks pelrun, yes the diode makes sense, so unless I'm pulling LOW, it'll not allow any current to flow. Ill do a bit of digging into an open collector setup Bryce sounds interesting, all good learning for me.
The diode actually gives you an open drain/open collector output without needing to add extra logic. Alternatively you can use a transistor to pull /WAIT low, but that also inverts the sense.
Quote from: GUNHEDIMHO that's made too easy for hardware creators. Yes, the way you describe it will work as long as the CPC uses exactly one expansion.
I didn't advocate for external expansions doing partial decoding at all - I was *only* describing the internal hardware. These days there's absolutely no reason not to do full decoding in expansion devices.
Agreed! But it can't harm to mention it now and then.
Any interest here in using the new RaspberryPi Pico (https://www.raspberrypi.org/products/raspberry-pi-pico/) as a CPC programmable peripheral ?
Programmable state machines for bit banging on IO pins independently of the two 133Mhz dual cores, looks interesting. And they certainly are cheap.
Quote from: revaldinho on 21:53, 26 January 21Any interest here in using the new RaspberryPi Pico as a CPC programmable peripheral ?
It needs to be considered that the I/O pins of the Pico must be 5V first, otherwise the Pico could be damaged by direct connection to the CPC.
Quote from: rpalmer on 22:14, 26 January 21Any interest here in using the new RaspberryPi Pico as a CPC programmable peripheral ?
Looks interesting, I'll do some reading up in it - I'd like to create a printer interface to read the Epson codes and output to a modern printer. I have been messing around with an esp32 and printing directly to port 9100 on my laser printer today, but I think it would be easier with an Rpi as there are libs available to convert Esc codes to PDF. I wonder if this would be useful for that.
Quote from: rpalmer on 22:14, 26 January 21
It needs to be considered that the I/O pins of the Pico must be 5V first, otherwise the Pico could be damaged by direct connection to the CPC.
Yes, a common problem with the modern CPLDs/FPGAs and MPUs. It would be nice if there were more parts with 5V tolerance available, and I am still sorry to have seen the demise of the XC9500 5V PLCC parts, but there are easy solutions given that you need to do a PCB to mount the part on the CPC anyway.
Hello all. As I don't have the necessary 'heavyweight' electronics skills, I've been approaching this topic using existing hardware.
First I built one of revaldinho's CPC-Ker-Plink co-processor cards and then installed a Raspberry Pi Zero WH along with a Waveshare USB/Ethernet HAT. This week I've been checking it co-exists with my other add-ons - so far so good.
It all went together without any problems and the photograph shows it on an expansion backplane with a memory card and FlashGordon. Now giving some thought about how to utilise SD Storage, 3 USB ports, WiFi and Ethernet.
I have some spare CPC-Ker-Plink PCBs.
Cheers.
Quote from: rpalmer on 22:14, 26 January 21It needs to be considered that the I/O pins of the Pico must be 5V first, otherwise the Pico could be damaged by direct connection to the CPC
The GPIO of the Pico seem to be 3.3V only. I guess that makes it a lot harder to connect it to the CPC then, right?
"The Raspberry Pi Pico's GPIO is powered from the on-board 3.3V rail and is therefore fixed at 3.3V"
Quote from: eto on 08:52, 31 January 21
The GPIO of the Pico seem to be 3.3V only. I guess that makes it a lot harder to connect it to the CPC then, right?
It's definitely less convenient.
I use 74LVC245s (https://www.digikey.co.uk/products/en/integrated-circuits-ics/logic-buffers-drivers-receivers-transceivers/704?k=74lvc245&k=&pkeyword=74lvc245&sv=0&pv69=411897&sf=0&quantity=&ColumnSort=0&page=1&stock=1&pageSize=25) for level shifting on my CPLink boards. These are cheap, readily available in 20 pin DIP packages and good for through-hole PCBs and breadboarding. If building PCBs then a large subset of 74 series logic is available in the LVC family (https://www.ti.com/lit/ug/scbd152b/scbd152b.pdf?ts=1612011672877) in SMD packages as well as these octal transceivers. In fact it you're happy with SMD soldering then there are a huge number of options here - this is what a quick search on Farnell (https://uk.farnell.com/w/c/semiconductors-ics/logic/level-shifters/prl/results?range=inc-in-stock%7Cexc-obs&st=logic%20level%20converter) shows up.
For breadboarding, you can find breakout boards using MOS based auto-sensing level shifter chips at many of the usual suspects, including
- sparkfun-level-translator-breakout-pca9306-1 (https://shop.pimoroni.com/products/sparkfun-level-translator-breakout-pca9306-1)
- sparkfun-logic-level-converter-bi-directional (https://shop.pimoroni.com/products/sparkfun-logic-level-converter-bi-directional)
- Adafruit 4 channel converter (https://uk.farnell.com/adafruit/757/logic-level-converter-4ch-arm/dp/2301651?st=logic%20level%20converter)
- Adafruit 8 channel converter (https://uk.farnell.com/adafruit/395/logic-level-converter-8ch-arm/dp/2301650?st=logic%20level%20converter)
I haven't tried any of these myself, but I think I have a couple here ready for experiments at some point. The real kicker is that these breakout boards are actually more expensive than the RaspberryPi Pico itself individually, and you're probably going to need 2 or three of them. At least in a breadboard they are reusable.
Aside from that you have any number of options of simple current limiting series resistors, potential dividers, or resistor-diode and resistor-transistor shifters.
So, it's all a bit of a pfaff but the Pico can still be an alternative to CPLD/FPGA based hardware design and very nearly all of those chips are also 3V3 only these days too.
Quote from: revaldinho on 21:53, 26 January 21
Any interest here in using the new RaspberryPi Pico (https://www.raspberrypi.org/products/raspberry-pi-pico/) as a CPC programmable peripheral ?
Programmable state machines for bit banging on IO pins independently of the two 133Mhz dual cores, looks interesting. And they certainly are cheap.
I guess that a VGA external card for the CPC should be possible. There is SIO code for VGA output and enough SRAM. Things as double-buffering, hardware sprites, hardware scrolling, 2D and 3D drawing hardware acceleration also could be done.