6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Fri Nov 22, 2024 5:29 am

All times are UTC




Post new topic Reply to topic  [ 8 posts ] 
Author Message
PostPosted: Thu Nov 11, 2021 5:21 pm 
Offline
User avatar

Joined: Tue Aug 11, 2020 3:45 am
Posts: 311
Location: A magnetic field
Shortly after getting an Arduino running, I wrote a Morse code library for its debug light. I thought this would save considerable time but it didn't for the very simple reason that I've been avoiding C and Arduino due to the bloat. After getting re-acquainted with 16 bit address-space systems via the AVR processor architecture, I found the 3KB Arduino base run-time overhead to be far too excessive. This is in addition to any system libraries, such as required for sprintf(), or my software which included 3.5KB for the Morse code debug library and 6.5KB for serial networking. I find this unworkable. Regardless, there is one part which can be salvaged.

The principle of a Morse code output library is good and can easily be implemented on 6502 using one or two pages of ROM. Indeed, it is of suitable scope for student exercise.

Trivial use of one debug light is grossly inefficient. Getting one bit of state from a development system, maybe, after remembering to deploy the correct version of test firmware is a very slow, tedious and error-prone method of diagnosing problems. It is possible but it will require many iterations of flashing firmware. At best, you will divide the problem by two. At worse, you will learn nothing or obtain false data.

There are more advanced techniques for extracting more bits of state from a system. I've suggested using odd values of blink lights to extract a diagnostic code. If you counted an even value then you counted wrong. Unfortunately, this trivial back-check becomes increasingly strained when conveying more than three bits of data. GARTHWILSON suggests using a piezo buzzer on pin PB7 of a 6522. This is a more advanced technique because it is possible to convey three or more bits of state via tone and a further two or more bits of state via duration. It also has the benefit that tone can be produced autonomously by a 6522 without halting the system. (Anyone who has used an ZX Spectrum will be *particularly* aware of the limitations of software controlled piezo tone generation.)

By using Morse code, it is possible to convey dozens or possibly hundreds of bits of state, with or without sprintf() or similar formatting. Furthermore, many of you are amateur radio enthusiasts or otherwise know Morse code and some of you, such as BigDumbDinosaur and drogon, already have an LED wired directly to the EMU pin of a 65816. You may find yourself in the lucky situation where you already know Morse code and have already implemented the necessary hardware. I wouldn't recommend a Morse code LED as a replacement for a 16*2 character LCD. However, it is not a desperate substitute. Well, unless you have the usual problems with a 16*2 LCD module.

One of the limitations of my Morse code library was to store the data in a one bit per byte format. Specifically, literal strings, such as "..---". This is obviously inefficient. A six symbol, null terminated string requires seven bytes and an array of 256 strings requires 1.75KB. The case statement compiled by avr-gcc was also quite inefficient; in part due to multiplication by seven to access array elements.

Many of these deficiencies can be solved in 6502 assembly and especially so if the lookup table can be compacted. In particular, I believe the table can be reduced to a one byte encoding such that the top three bits define one of eight cases. Furthermore, the encoding is very amenable to branching and serialization on 6502.

Code:
LSB           MSB
 x P P x x 0 0 0 - Where PP is for different length pauses for space, comma, full stop or other punctuation.
 S x x x x 1 0 0 - Where S is for Morse encodings with one symbol. ("E" or "T".)
 S S x x x 0 1 0 - Where SS is for Morse encodings with two symbols.
 S S S x x 1 1 0 - Where SSS is for Morse encodings with three symbols.
 S S S S x 0 0 1 - Where SSSS is for Morse encodings with four symbols.
 S S S S S 1 0 1 - Where SSSSS is for Morse encodings with five symbols.
 S S S S S 0 1 1 - Where SSSSS is for Morse encodings with six symbols ending with dot.
 S S S S S 1 1 1 - Where SSSSS is for Morse encodings with six symbols ending with dash.


On 6502 or 65816, it is possible to pass a string pointer to a Morse code output routine via two consecutive memory locations in zero page. Such a calling convention may also define a string length or require a null terminated string.

The Morse code conversion may be implemented with LDA (TABLE,X). A copy of the lookup table entry can be pushed on stack with PHA. After bit shifts and a bit mask, TAX // PLA // JMP (CASE,X) applies the top three bits of the lookup table entry to an 8 address (16 byte) jump table while keeping the original lookup table entry in RegA. Jump case zero performs another bit mask and a further JMP (PAUSE,X). The remaining six distinct cases may fall through while performing 1-6 iterations of dot or dash display using ROR // BCS. (Case six and case seven have the same implementation.)

A minor source of difficulty is the lack of portable timer or output port. This applies equally to 6502/65816 and AVR.

For timing, it is possible to reduce everything to multiples of one pause unit and then implement this pause with idle loops. For example, it is possible to define WAITDASH as JSR WAITDOT // JSR WAITDOT // JMP WAITDOT (or fall through to WAITDOT). It is then possible to implement WAITDOT using nested loops which use RegX and RegY. The intention of the idle loop is to wilfully consume a fixed number of processor cycles. You may want to find suitable loop boundary values empirically. You may also wish to preserve registers if you are indexing through a string.

On 65816, the output port may be the EMU pin. In this case, output of a dot would be SEC // XCE // JSR WAITDOT // CLC // XCE. This would raise and lower the EMU pin with the desired duration. This sequence or a similar sequence for dash can be selected using ROR // BCS. In other cases, it may be possible to flip one bit of an I/O port. Unfortunately, the address of the port and the bit to be flipped is arbitrary. Fortunately, this information can be supplied as parameters.

If you wish to halt a system and continuously display a message, it is possible to call the Morse code output routine within an endless loop. Parameters should be arranged such that the string is not consumed. Specifically, the pointer to the start of the message must be retained in some manner.

You may wish to implement a full 256 byte lookup table. This allows trivial encoding of Latin1 symbols (or Greek or Cyrillic). Alternatively, it is trivial to cap the table at 128 entries. With further manipulation, it is possible to fold upper case and lower case such that 96 or 102 bytes are required. However, this doesn't save much space. Likewise, I don't recommend elimination of the 32 ASCII control codes for the very simple reason that CHR(10) (line feed) and CHR(13) (carriage return) may be usefully mapped to pauses. Anyhow, depending upon preferences, a large implementation may not exceed 400 bytes and the smallest implementation will be less than 256 bytes.

If you want to get fancy, it is possible for a completely different implementation to work via periodic interrupt. In this case, a string would be loaded into a dedicated buffer and a small amount of state would be required to maintain progress through each dot, dash or gap. This would allow a message to be output indefinitely or for a finite number of viewings while other activity occurs. Unfortunately, a trivial LED connected to 65816 EMU pin and updated via interrupt is mutually exclusive with 65816 native mode. For this reason, I recommend connecting trivial LEDs to an I/O port with read-back, such as the LE74HC574K245N and primarily using digital LEDs with 65816 EMU pin.

_________________
Modules | Processors | Boards | Boxes | Beep, Beep! I'm a sheep!


Top
 Profile  
Reply with quote  
PostPosted: Thu Nov 11, 2021 8:16 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8543
Location: Southern California
I haven't tried Morse with the 65xx, but I've done it with my HP-41cx calculator/computer to a minor extent, with synthetic programming. I believe doing it with sound will afford much higher speeds than you could read with an LED. The world speed record is something like 75wpm which is quite a bit faster than I can type.

People who aren't experienced in Morse also don't realize that it's not really sterile, that yes, you can perceive inflections, recognize a sender's "voice" if he's doing it by hand instead of generating it with a computer, etc.; and that with all the abbreviations, Q codes, etc., you actually go considerably faster than the number of wpm suggests. When I was using Morse a lot 40 years ago, I could listen to it at 30wpm and read a magazine at the same time and get most of both. I did this when I was talking with someone and was trying to find something in an article in a ham-radio magazine while he was talking.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
PostPosted: Thu Nov 11, 2021 11:25 pm 
Offline
User avatar

Joined: Sun Jun 30, 2013 10:26 pm
Posts: 1949
Location: Sacramento, CA, USA
Slightly off-topic: I'm reminded of the OBD-1 vehicle emissions control systems trouble code retrieval systems I still see stumbling into work from time-to-time. Diagnosing involves connecting a jumper wire then reading blinks on one or sometimes more LEDs. The most common have two-digit trouble codes that are formatted (as an example)
. . . blink . blink . . blink . blink . blink . . . blink . blink . blink . . blink . . .
for 23, 31, where each dot is a short pause interval. Primitive, but effective.

Attachment:
obd1dtc.PNG
obd1dtc.PNG [ 26.11 KiB | Viewed 1173 times ]

_________________
Got a kilobyte lying fallow in your 65xx's memory map? Sprinkle some VTL02C on it and see how it grows on you!

Mike B. (about me) (learning how to github)


Top
 Profile  
Reply with quote  
PostPosted: Fri Nov 12, 2021 12:59 am 
Offline

Joined: Thu Jan 21, 2016 7:33 pm
Posts: 282
Location: Placerville, CA
barrym95838 wrote:
Slightly off-topic: I'm reminded of the OBD-1 vehicle emissions control systems trouble code retrieval systems I still see stumbling into work from time-to-time. Diagnosing involves connecting a jumper wire then reading blinks on one or sometimes more LEDs. The most common have two-digit trouble codes that are formatted (as an example)
. . . blink . blink . . blink . blink . blink . . . blink . blink . blink . . blink . . .
for 23, 31, where each dot is a short pause interval. Primitive, but effective.

Or the POST beeps on PCs. Yeah, sometimes all you need is just that little bit of information telling you where to start looking.


Top
 Profile  
Reply with quote  
PostPosted: Fri Nov 12, 2021 6:54 pm 
Offline
User avatar

Joined: Sun Nov 07, 2021 4:11 pm
Posts: 101
Location: Toronto, Canada
barrym95838 wrote:
Slightly off-topic: I'm reminded of the OBD-1 vehicle emissions control systems trouble code retrieval systems I still see stumbling into work from time-to-time. Diagnosing involves connecting a jumper wire then reading blinks on one or sometimes more LEDs. The most common have two-digit trouble codes that are formatted (as an example)
. . . blink . blink . . blink . blink . blink . . . blink . blink . blink . . blink . . .
for 23, 31, where each dot is a short pause interval. Primitive, but effective.


Our furnace works exactly that way… we had some trouble with it a few years ago and I became much more intimately familiar with this debugging method than I care to admit :-)


Top
 Profile  
Reply with quote  
PostPosted: Fri Nov 12, 2021 7:43 pm 
Offline

Joined: Fri Dec 21, 2018 1:05 am
Posts: 1117
Location: Albuquerque NM USA
The take-away of this rather long story is "blinking" the light. First light-on says something important followed by light-off indicating further progress and second light-on provides even more data. The duration of on and off are also meaningful. I'm very fond of my blinking light and I also look at the current meter of my bench power supply for more information. In fact, my eyes are glued to the current meter when I turned on a newly assembled board and ready to pull plug if current is excessive.
Bill


Top
 Profile  
Reply with quote  
PostPosted: Fri Nov 12, 2021 11:01 pm 
Offline
User avatar

Joined: Wed Feb 13, 2013 1:38 pm
Posts: 589
Location: Michigan, USA
There are lots of different ways to represent Morse elements in a table and to decode them. Here's one example (below) where from left to right a '1' bit represents a dash and a '0' bit represents a dot with a '1' bit terminator on the right;

Have fun...

Code:
;******************************************************************
;
;
;    rom char morse[] = { 0b11001110,   // ',' (44) dah-dah-di-di-dah-dah
;                         0b10000110,   // '-' (45) dah-di-di-di-di-dah
;                         0b01010110,   // '.' (46) di-dah-di-dah-di-dah
;                         0b10010100,   // '/' (47) dah-di-di-dah-dit
;                         0b11111100,   // '0' (48) dah-dah-dah-dah-dah
;                         0b01111100,   // '1' (49) di-dah-dah-dah-dah
;                         0b00111100,   // '2' (50) di-di-dah-dah-dah
;                         0b00011100,   // '3' (51) di-di-di-dah-dah
;                         0b00001100,   // '4' (52) di-di-di-di-dah
;                         0b00000100,   // '5' (53) di-di-di-di-dit
;                         0b10000100,   // '6' (54) dah-di-di-di-dit
;                         0b11000100,   // '7' (55) dah-dah-di-di-dit
;                         0b11100100,   // '8' (56) dah-dah-dah-di-dit
;                         0b11110100,   // '9' (57) dah-dah-dah-dah-dit
;                         0b10000000,   // ':' (58) null
;                         0b10000000,   // ';' (59) null
;                         0b10000000,   // '<' (60) null
;                         0b10000000,   // '=' (61) null
;                         0b10000000,   // '>' (62) null
;                         0b00110010,   // '?' (63) di-di-dah-dah-di-dit
;                         0b10000000,   // '@' (64) null
;                         0b01100000,   // 'A' (65) di-dah
;                         0b10001000,   // 'B' (66) dah-di-di-dit
;                         0b10101000,   // 'C' (67) dah-di-dah-dit
;                         0b10010000,   // 'D' (68) dah-di-dit
;                         0b01000000,   // 'E' (69) dit
;                         0b00101000,   // 'F' (70) di-di-dah-dit
;                         ~~~~
;                         0b10011000,   // 'X' (88) dah-di-di-dah
;                         0b10111000,   // 'Y' (89) dah-di-dah-dah
;                         0b11001000 }; // 'Z' (90) dah-dah-di-dit
;
; /*
;  *  a self-contained function hard coded, so to speak, for 20-wpm
;  *  (60-ms dit time) Morse with a 600-Hz tone.
;  */
;
;  void putmorse(char rxchar)           //
;  { static unsigned char mchar = 128;  // default null pattern
;    if(rxchar >= 97) rxchar -= 32;     // lower to upper case alpha
;    if((rxchar>=44) && (rxchar<=90);   // if rxchar in array range
;      mchar = morse[rxchar-44];        // get morse dit/dah pattern
;   /*                                                                *
;    *  send Morse dit/dah elements, 'mchar' = 128 (null) on exit     *
;    *                                                                */
;    while(mchar != 128);               // while dits/dahs remaining
;    { unsigned char tone = 36;         // 60-ms 600-Hz dit (20 wpm)
;      if(mchar.7) tone = 108;          // 180-ms 600-Hz dah  "  "
;      while(tone--)                    // send a 600 Hz dit or dah
;      { porta.0 = 1; delay_us(833);    // 1/2 of 600 Hz period
;        porta.0 = 0; delay_us(833);    // 1/2 of 600 Hz period
;      }                                //
;      delay_ms(60);                    // inter-element 1 dit space
;      mchar <<= 1;                     // shift for next iteration
;    }                                  //
;    delay_ms(2*60);                    // inter-char space (3)
;    if(rxchar == ' ') delay_ms(4*60);  // inter-word space (7)
;  }                                    //
;
;
;******************************************************************


Top
 Profile  
Reply with quote  
PostPosted: Sun Feb 27, 2022 2:15 pm 
Offline
User avatar

Joined: Tue Aug 11, 2020 3:45 am
Posts: 311
Location: A magnetic field
There are times when I write and I think "If no-one else gets this, barrym95838 will." Indeed, given barrym95838's experience will mission-critical systems, such as vehicle electronics, I assumed that barrym95838 would have an intuitive understanding of top tier diagnostic techniques. Likewise, if there is a good practice, GARTHWILSON was doing it effortlessly before the whippersnappers were born.

I've been considering a one byte, two hex digit diagnostic scheme since I worked on a hydroponic system a few years ago. There is several complications when non-technical people are expected to read and report diagnostic codes. Firstly, blink codes and similar should be tolerant to color blindness. Secondly, codes should be portable across systems. Raspberry Pi diagnostics fail this condition. For example, three blinks means different things on different models. This requires people to accurately report the diagnostic code and the model.

Thirdly, for digit diagnostics, codes should be tolerant of digit transposition. This can be achieved by restricting codes to ascending/descending order only. It might also be worthwhile to make codes readable at any orientation. So, for example, don't allow $33/$EE or $66/$99 on seven segment display. Actually, it might be worthwhile to skip hexadecimal and only use decimal. Much of this conflicts with wanting to group diagnostic codes into meanful categories.

There is more much more fundamental problem. What should happen there are multiple errors?

_________________
Modules | Processors | Boards | Boxes | Beep, Beep! I'm a sheep!


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 8 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 10 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:  
cron