6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sun Nov 10, 2024 4:58 pm

All times are UTC




Post new topic Reply to topic  [ 51 posts ]  Go to page Previous  1, 2, 3, 4  Next
Author Message
PostPosted: Sun Oct 25, 2015 4:35 am 
Offline

Joined: Wed Sep 23, 2015 8:14 pm
Posts: 171
Location: Philadelphia, PA
Brief update:

I've left the 68B50 in place for now so I have a "debugging port". I added another 74HC138 to decode more address lines so now I can attach up to eight hardware peripherals and tested it to insure it works. No problems up to 7.37 MHz at 5V, despite the longer logic paths.

Since I'm out of room on my original 3-piece solderless breadboard, I've grabbed another breadboard and put the PIC24FJ32 on it along with the 74LVX4240 level translator and 3.3 Volt regulator. I still have three 5V lines coming into the PIC that aren't being translated so I've added 220-ohm series resistors and Schottky diodes to the 3.3 Volt rail to supplement the protection diodes already on the PIC. If that doesn't work well, I'll go ahead and solder the other 74LVX4240 and use it. I was hoping to switch the entire system over to 3.3 Volts, but Mouser screws up the shipping on about 50% of the orders I place with them and I didn't get lucky this week (of course they charge about half what Digikey does for shipping, or I wouldn't bother with them at all).

I've also started on the code for the PIC-UART and hope to test it soon. I'd say tomorrow except I've got an old HP 1660A completely disassembled that I was hoping to get working again so I can use it to debug with (it started power cycling itself a couple of years ago shortly after power on and when I took it apart, I nearly choked to death on all the dust that was inside). My PICO-scope is handy, but the 16-port logic analyzer on it is woefully lacking in ports compared with up to 256-ports I get on the 1660A.

Edit: spelling correction.


Top
 Profile  
Reply with quote  
PostPosted: Tue Oct 27, 2015 2:28 am 
Offline

Joined: Wed Sep 23, 2015 8:14 pm
Posts: 171
Location: Philadelphia, PA
I did some testing with the PIC24FJ32 earlier this evening. First, I verified the tuneable range of the on-board RC oscillator. It is nominally 8 MHz. I found the minimum and maximum values to be:

F(min) = 6.886 MHz
F(max) = 9.078 MHz

This was at room temperature.

Next I did a bit of legwork to find the closest approximation to 7.3728 MHz (all common baud rates divide into this number) which wound up being 7.384 MHz. That's 0.15% high, but probably well within the tolerance of RS232 communications, so long as the frequency doesn't drift too much with temperature.

Finally, I started to integrate the PIC-UART into the 65C02 bus in preparation for testing the bus interface on the PIC. I noticed that while the wait state circuit is holding RDY low for an extra cycle just like it's supposed to do, the WRn signal is still toggling with PHI2 while RDY is low. This didn't seem to bother the 68B50, but it definitely would violate the PIC PMP timing diagrams so I need to fix it before moving forward. I think I can do it with a single NAND gate which should be available. Once that's working properly, I'll be ready to test the parallel ports. Assuming they work as expected, a working UART will not be far behind. I am very curious to see how far I can push it, both in terms of bus frequency and in terms of serial port speed.


Top
 Profile  
Reply with quote  
PostPosted: Wed Oct 28, 2015 3:19 pm 
Offline

Joined: Wed Sep 23, 2015 8:14 pm
Posts: 171
Location: Philadelphia, PA
I made some progress fixing the WRn write pulse, but I seem to be facing a timing issue now.

Here is the logic analyzer showing the old timing before the fix. You can see the RDY signal is perfect, but the WRn pulse toggles with CLK which is not what the peripheral expects (key for which traces correspond to which signals is at the bottom of the window):

Attachment:
File comment: Wait state with incorrect WRn pulse
wait_old.png
wait_old.png [ 102.39 KiB | Viewed 1513 times ]


The above timing worked fine with the 68B50 UART, but that's probably just dumb luck and I don't want to take chances with the PMP on the PIC.

So I modified the circuit generating the WRn pulses and now I have this timing:

Attachment:
File comment: Wait state with correct WRn pulse
wait_new.png
wait_new.png [ 124.08 KiB | Viewed 1513 times ]


But unfortunately the system no longer works correctly. In particular, the PIC18 still programs the "ROM" correctly, but when control is transferred to the 65C02, EhBASIC doesn't work correctly. My best guess is that the tiny additional logic delay to the WRn signal is now late enough that the data lines have started to change while the write pulse on the CY7C199 memories is still low -- at least for a few nanoseconds -- which apparently is long enough to change their contents to other than what they should be.

When RDY is not asserted, the WRn logic works exactly as it did in the first diagram. The only difference now is that there is one more 74HC00 gate delay in the path of the clock signal. I could try to fix this by replacing the 74HC00 with a 74AHC00 gate, but I'd prefer to avoid going down that path until later when I want to push the speed of the 65C02 to the limit. Instead, I'm thinking that why not run the PHI2 signal through a couple of inverters and then use this delayed clock to supply PHI2 to the entire system, except for the WRn logic which can use the non-delayed PHI2 signal. I've used similar techniques on FPGA designs when they had to interface with external asynchronous devices with success, so it seems a reasonable path to go down.

If there is a better way I haven't considered, I'd be happy to hear of it. Hopefully something short of running a PLL that will allow me to implement arbitrary phase delays into my clocking signals though! :)

Edit: In the two images above, the logic analyzer output D2 is erroneously labeled as RDn (read strobe). It is in fact connected to the RWB pin on the 65C02.


Last edited by jmp(FFFA) on Thu Oct 29, 2015 11:41 am, edited 1 time in total.

Top
 Profile  
Reply with quote  
PostPosted: Wed Oct 28, 2015 5:13 pm 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8479
Location: Midwestern USA
Not sure if this will help you any, but here is the logic I am using in POC V2's CPLD to control the /RD and /WD signals:

Code:
RD        = RWB & (PHI2 # rdyout) & vab;       /* active low read            */
WD        = !RWB & (PHI2 # rdyout) & vab;      /* active low write           */

In the above, & is logical AND and # is logical OR. Terms are:

Code:
PHI2     system clock
RWB      read/write output from microprocessor
rdyout   true if a wait-state is being applied; active high
vab      true if valid address bus (65C816); active high

So, you need to logically OR the Ø2 clock with a signal that goes high (rdyout in the above) while a wait-state is in progress. The product of that is then logically ANDed with RWB to produce a valid /RD signal. Ditto for a /WD signal, except for the inversion of RWB. The result is that /RD and /WD will remain stable during the wait-state.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
PostPosted: Wed Oct 28, 2015 5:58 pm 
Offline

Joined: Wed Sep 23, 2015 8:14 pm
Posts: 171
Location: Philadelphia, PA
Thanks BDD.

Here is the logic I am using for WRn (your /WR)

WRn = RW | (RDY & !CLK)

I believe this logic is correct (and the 65C02 doesn't have a VBA pin or equivalent so I can't use your logic without modification). I still believe I'm experiencing some sort of timing problem, since if I replace the above logic with this:

WRn = RW | !CLK

By removing one gate, the system works again. However, if I wire the RDY input high in the first equation, which produces exactly the same logic as the second but adds one gate delay, the system still fails.


Top
 Profile  
Reply with quote  
PostPosted: Thu Oct 29, 2015 2:02 am 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8479
Location: Midwestern USA
jmp(FFFA) wrote:
Here is the logic I am using for WRn (your /WR)

WRn = RW | (RDY & !CLK)

What is defining the RW term? Please show me the logic for RW.

Quote:
...and the 65C02 doesn't have a VBA pin or equivalent so I can't use your logic without modification.

Just rewrite the equations as:

Code:
RD =  RWB & (PHI2 # rdyout);  /* active low read  */
WD = !RWB & (PHI2 # rdyout);  /* active low write */

for the 65C02. While you are staring at those two equations see if you can identify a fundamental difference between what you are doing and what I am doing. Keep in mind that RWB is the MPU's output signal, not one generated by intermediate logic equations. This logic works glitch-free.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
PostPosted: Thu Oct 29, 2015 3:27 am 
Offline

Joined: Wed Sep 23, 2015 8:14 pm
Posts: 171
Location: Philadelphia, PA
BigDumbDinosaur wrote:
What is defining the RW term? Please show me the logic for RW.

Sorry I wasn't more clear. RW is the 65C02 RWB pin.

So, to restate:

Code:
WRn = RWB | (RDY & !CLK)
RDn = !RWB | (RDY & !CLK)


Where WRn is my active low write strobe, and RDn is my active low read strobe. Here I've used C-language syntax for nots, ors and ands. RDY is the signal level applied to the 65C02 RDY pin (low during a wait state), and CLK is PHI2. I stated earlier that I think this logic is correct, but that I had run into a timing issue based on the evidence at hand.

Looking more closely at the logic analyzer output (at a higher time resolution), it was apparent that the address bus had started to change before WRn (write strobe) returned high. The extra logic levels in the WRn path had finally added up enough to cause this problem. Since I'm using 15nS memory, it didn't take much for it to become corrupted. Fixing this was as simple as adding a single-gate delay to the PHI2 input to the 65C02 and all is working again.

I'm now seeing exactly the expected behavior for the RDY line and the read and write strobes on the logic analyzer and limited system testing with EhBASIC shows no problems. So hopefully I can now go back to testing the PIC-UART.


Top
 Profile  
Reply with quote  
PostPosted: Sun Nov 01, 2015 3:14 am 
Offline

Joined: Wed Sep 23, 2015 8:14 pm
Posts: 171
Location: Philadelphia, PA
The PIC-UART is progressing nicely now that I've worked through the voltage translation, wait state and timing issues. I've tested reads and writes to the four separate addresses with the bus running around 4 MHz and it works flawlessly. I'm not going to push the speed limits until I have the UART functionality working.

The MC6850 emulation code is ready for testing next.

I hope that 16 MIPS and a 4-cycle interrupt latency will be fast enough. A reset sequence on the MC6850 involves writing a particular pattern to the config register, followed by writing the desired configuration settings to it again. If those writes happen back to back on a system clocked at 14 MHz, I doubt the PIC will be fast enough to catch them both. That is really the only scenario I can think of where it may not be 100% transparent to the software.

I haven't looked at the 6551 registers carefully yet to see if there might be any similar issues there. The only scenario that may cause a problem is the CPU is clocked at a fast speed and does back-to-back writes. For I/O, it should write, then either poll or wait for an interrupt which won't be a problem.


Top
 Profile  
Reply with quote  
PostPosted: Thu Nov 05, 2015 6:13 pm 
Offline

Joined: Wed Sep 23, 2015 8:14 pm
Posts: 171
Location: Philadelphia, PA
I've created a github repository for the PIC-UART code:

https://github.com/jason6502/pic-uart

The initial check-in implements a mostly MC6850-compatible device (within the limits of the PIC hardware). It compiles, but is not yet tested, so I anticipate further changes will be necessary to fix bugs. In the meantime I welcome any comments or suggestions for improvements. Once I get this working, and time allowing, I'll add 6551 emulation as well -- unless someone else beats me to it. :)

It's currently 100% C, and I hope to keep it this way if possible for portability.

I'm still thinking of following up with PIC-SPI and PIC-I2C on the same platform if this works out reasonably well.

Edit: It's now at least partially working. Outputting "Hello World" at speeds from 1200 baud through 38400 baud. Will do more extensive testing over the weekend and hopefully declare at least the enhanced MC6850 mode working by then.


Top
 Profile  
Reply with quote  
PostPosted: Fri Nov 06, 2015 7:11 pm 
Offline

Joined: Wed Sep 23, 2015 8:14 pm
Posts: 171
Location: Philadelphia, PA
Now that the basic, "Hello, World" tests are passing, it's time to work on a more comprehensive test plan for the pic-uart, after which I can call it a 1.0 release. These are the tests I'm planning at present:

  • Closely spaced writes to the configuration register. Verify that the following code properly configures the PIC:
    Code:
        LDA #INIT
        STA UART
        LDA #CONFIG
        STA UART
  • High speed output. Configure a high baud rate like 460800 and then use a machine language subroutine to output a few thousand characters and check them for errors.
  • High speed input. Configure a high baud rate like 115200 (dependent on how fast the 6502 can process the input) and then input a few thousand characters from a PC. Verify that they were received correctly.
  • Repeat above two tests with no parity, even parity, and odd parity.
  • Repeat above tests with different crystal frequencies (up to about 8 MHz).
  • Repeat above tests at several different baud rates.
  • Configure UART for interrupt generation and verify it produces interrupts for the following conditions: receive data register full, transmit data register empty, and at least one error condition that is easily generated (overflow).

Once it passes the above tests, or at least once some reasonable limits are found within which it works correctly, I will make a 1.0 release. Subsequent releases will focus on extending any limits that are found (e.g. allowing it to run at higher speeds) and possibly adding 6551 compatibility as well. I'm also tempted to make a parallel effort for pic-spi and pic-i2c to provide a simple bus-interface to these two popular serial protocols using the methods already being used by the pic-uart.


Top
 Profile  
Reply with quote  
PostPosted: Sun Nov 08, 2015 5:04 am 
Offline

Joined: Wed Sep 23, 2015 8:14 pm
Posts: 171
Location: Philadelphia, PA
Spent some time testing the PIC-UART today and I think I'm ready to declare it beta quality. There's always more testing to be done, but it's working well enough to work with EhBASIC at baud rates up to 57600 and at 65C02 bus speeds up to 4 MHz (with 1 wait state, though I'm not sure that's really necessary at these bus speeds). To go further with testing, I'm going to need to write some dedicated machine language testing functions to push the performance envelope to the limit and beyond. If anyone knows of any easily ported file transfer software with error detection (e.g. xmodem), that would probably also be ideal for testing as well.

It sure is nice to be able to change baud rates without having to mess with hardware. Unlike the 6551, you're not limited to 19200 baud (max programmable speed), either. I gather there are a few hard-to-find DIP UARTs out there like this if you're willing to part with $20 or more for one of them.

There was one timing hazard in the software which proved to be difficult to fix. When you write to the PIC bus output registers, the PIC clears the flags indicating that these buffers are empty. A timing hazard comes about because the bus is accessed by the 65C02 asynchronously and if the PIC writes to those buffers during a brief window when a bus read has been initiated by the CPU but the ISR on the PIC has not yet been called, it will clear these flags. The problem is these flags are used to inform the ISR of which register was just read. I don't think the Microchip intended the PMP port to be used for this type of application, so it's a bit awkward to work with. The following diagram from the PIC24F reference manual serves to illustrate the problem:

Attachment:
File comment: PMP Timing
pmp-timing.png
pmp-timing.png [ 17.9 KiB | Viewed 1371 times ]


When the 65C02 initiates a read from the PIC, the OBE line becomes active four cycles before the interrupt is initiated (which itself takes several more cycles). Ordinarily, this would be a very small window for the hazard to express itself. Unfortunately, the portion of the code that writes to the output registers needs interrupts masked for synchronization purposes. If the 65C02 initiates a bus read while this mask is active, the interrupt code doesn't work correctly when it is invoked after interrupts are unmasked since the OBE line is cleared by the write to the output registers.


Last edited by jmp(FFFA) on Sun Nov 08, 2015 5:26 am, edited 1 time in total.

Top
 Profile  
Reply with quote  
PostPosted: Sun Nov 08, 2015 5:23 am 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8479
Location: Midwestern USA
jmp(FFFA) wrote:
I gather there are a few hard-to-find DIP UARTs out there like this if you're willing to part with $20 or more for one of them.

Here's one in 40 pin DIP that is well under $20.

That said, why force yourself to be limited to a package that is rapidly becoming unobtanium with these specialized ICs? You can use PLCC sockets on 100 mil perf board, you know.

Quote:
There was one timing hazard in the software which proved to be difficult to fix.

:) It seems like a lot of hoop-jumping to avoid using a real UART...one that may be had for less than $10. :) Just my curmudgeonly observation.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
PostPosted: Sun Nov 08, 2015 6:00 am 
Offline

Joined: Wed Sep 23, 2015 8:14 pm
Posts: 171
Location: Philadelphia, PA
BigDumbDinosaur wrote:
Here's one in 40 pin DIP that is well under $20.

OK, I stand corrected. It's only three times more than the PIC24FJ32 I'm using, uses up more breadboard space, and doesn't support higher baud rates. It's also not an option at all if you're running a 3.3V system.

BigDumbDinosaur wrote:
That said, why force yourself to be limited to a package that is rapidly becoming unobtanium with these specialized ICs? You can use PLCC sockets on 100 mil perf board, you know.

Isn't there a thread from about 10 years ago predicting that analog VGA would be obsolete too in 5 years? Frankly there is no faster way to prototype simple low-speed circuits. The day I can no longer do basic prototyping with solderless breadboard will be the day I give up electronics for another more accessible hobby (but I am perfectly willing to use DIP adapters when possible). :)

Quote:
:) It seems like a lot of hoop-jumping to avoid using a real UART...one that may be had for less than $10. :) Just my curmudgeonly observation.

Perhaps it is, but then again using a real UART wouldn't offer a nice segue into a PMP-based SPI and I2C interface either! :) I'm actually fairly pleased with how well the PIC-UART has turned out so far. I wasn't sure it would be usable at all yet it is already working nicely in place of the real UART (MC6850) on my test system.


Top
 Profile  
Reply with quote  
PostPosted: Sun Nov 08, 2015 6:09 am 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10976
Location: England
> It seems like a lot of hoop-jumping to avoid using a real UART

I think it's not so helpful to deny the premise of a thread. This thread is about using a microcontroller to emulate a UART.

I don't fully understand that race condition, but I see that it's a bit of an obstacle to making a reliable system. Let me try to summarise what I believe is going on:
- From outside the PIC, we want to read a register which the PIC is providing
- The (external) micro starts a read access
- The PIC gets an interrupt
- The PIC's interrupt handler starts up
- The interrupt handler reads a flag register which records which register the micro wanted to read
- The interrupt handler provides the data appropriate to that register
- The micro gets the data it wanted

The problem is that the same 'flag register' is used by the hardware to communicate to the interrupt handler which register is wanted, as well as recording which registers are full (not yet read) or empty (have been read)

If the non-interrupt code wants to place data into the output register, it needs to write to this same flag register, and this write can be in a race against the write the hardware does on an external read.

Can you instead arrange that the non-interrupt code places outgoing data into a circular buffer, and let the interrupt handler deal with moving data from the buffer to the output register?


Top
 Profile  
Reply with quote  
PostPosted: Sun Nov 08, 2015 7:22 am 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8479
Location: Midwestern USA
BigEd wrote:
> It seems like a lot of hoop-jumping to avoid using a real UART

I think it's not so helpful to deny the premise of a thread. This thread is about using a microcontroller to emulate a UART.

Ed, do you have a problem with others stating their opinions? I didn't say that he shouldn't do it, or that he was stupid for doing it, or anything else, for that matter, that was derogatory. I was merely making an observation.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 51 posts ]  Go to page Previous  1, 2, 3, 4  Next

All times are UTC


Who is online

Users browsing this forum: No registered users and 4 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: