i2c-setup is indeed never called in my code. The VIA (65C22) is reset (hardware reset) along with all the other chips on my board at powerup and those registers (via.porta (called ORA in the datasheet) and via.ddra) are both zeroed on reset. Unfortunately, WDC's datasheet is not very clear on that so I had originally written this word with the plan of calling it on powerup. Now I only call i2c-setup (manually) if I have messed up the configuration of my via and don't want to reset the board.
I'll also just mention that the . in the names I used for the registers doesn't mean anything to Forth and are just part of the name (eg. they could have also been named
via-ddra or
via/ddra or
viaddra as those are all valid forth word names). I just use the dot syntax because I'm used to that from other languages and it helps me keep all of the names for a particular piece of hardware sorted.
If you need it to be called at startup in your code, then you can just call the i2c-setup word down near where the vectors are loaded, eg:
Code:
\ Connect to Fourth BLOCK words
i2c-setup \ Initialize the VIA hardware
' eeprom-blockread BLOCK-READ-VECTOR !
' eeprom-blockwrite BLOCK-WRITE-VECTOR !
For debugging your code, the awesome part about Forth is that you can define a word, run it, and then poke around in memory and hardware to see what happened. Want to make sure that the VIA registers are still initialized? You can just type in:
Code:
via.ddra c@ . via.porta c@ .
to see what the current values in the hardware are. If you are having trouble with a word, you can try running it line by line (by pasting a line in, running just that line, and then investigating what happened).
One note about interpreted mode, where you are just typing things in and running them directly, is that the flow-control words are compile-only words (they will tell you that if you forget and try to use them in interpreted mode). This means if you have a loop that need to run 8 times, you can't use DO and LOOP in interpretive mode. If I need to "step" through the code in the loop, I will paste the guts of the loop multiple times. If
I is used in a do-loop then I just put the value I want "I" to be.
This is doable for smaller loops but impractical for larger loops, like your 64-byte EEPROM sector writing code). In that case, I might "single-step" (by running individual lines) through the loop code once or twice to make sure the logic inside works properly, and then I will define a word that has only that loop in it. If I was hunting down nACK problems, I would probably make a word that does all but the last byte and then I would do that last byte step by step and use a multimeter or logic probe on the hardware as well as
.S to see what was on the stack (without disturbing it). I2C is nice in that you control the clock and there is no minimum speed for most devices, so it's OK to pause in the middle of sending a byte and make sure everything looks good before continuing.
If you keep your debugging code in a text editor while you are working, you can make
reproduceable code that will get you from idle to the very last byte of a transfer reliably that you can just copy/paste. I'll often make a test word that I keep adding the "known good" code to - so I can progress right up to the point of interest by running the test word. Forth lets you re-define a word by just defining it again - only the most recent is run (the older ones do still take up dictionary space, but they will be gone on reset). I'll also make a word that prints out all of the values in the important memory and hardware locations. Once you have your logic or hardware figured out and fixed up, then you take what you learned and put it in the final version of the word. I often abandon my debugging code once I have the real-deal working, but you certainly could save it - especially if you made some extra words to test hardware that might be useful later.
Words you will want for debugging:
.S DUMP @ C@ . and Tali also has CTRL-P and CTRL-N to recall the previous/next line of the last 8 lines entered.