Saturday, February 28, 2015

"Cyprida 2" already in the works?

While working on the Cyprida project I think about possible enhancements.

While searching for a retroilluminated 4x40 text LCD display I found this one on Futurlec ($44.90, ouch!): apparently its page has an error in the Interface Pin Connections because it only lists a single "E" (enable) pin, while a 4x40 LCD needs two (namely "E1" for the upper 2 lines, and "E2" for the lower 2 lines). And it does not say if the internal font is the Euro/USA one or the Japanese one:


So I started searching for a 320x200 display (320x200 is 64000 pixels with 16:10 aspect ratio), which I consider more interesting than a 320x240 display (76800 pixels and a 4:3 aspect ratio).

Futurlec also has some fancy blue 320x240 graphic display but the price is far from being interesting ($119.90); its controller accepts Seiko SED1335 commands, vaguely resembling Hitachi HD44780 ones, but with more operations about graphics and overlays. Apparently it does not have simple operations like "draw pixel, draw diagonal line", which need to be implemented in the Arduino (at a higher cost). This is because those displays were intended for monitoring data, not for experimenting with graphics or emulating home computers...


Spanish supplier of the Shenzen Topway has a nice 320x200 "green on black" monochrome graphic display. Sadly I can't find the commands list - I guess it is a SED1335-type. No pricing information available (grunt!).


It also features a nice "black on yellow" 4x40 text LCD display:


A very nice 5.7" 320x240 64k-color display is available as well, with a complete firmware (functions like "draw pixel", "draw line", "fill circle" and so on) and even a RS232 port for commands. It would be great to have it on my future "Cyprida 2" project. I am only unable to figure out a price...


Friday, February 27, 2015

Browsing components suppliers websites brings lots of ideas

I was searching Distrelec for a 4x40 LCD display (they don't have it, and their displays are quite expensive), and instead found this case:
I only need to apply something like it on Cyprida's 4x40 LCD display... which has a view area of about 154x28mm and a metallic black border of 173x48mm.

The above product has a 145x28mm window and is 161x40. Oops: too small! The biggest one available is 169x27mm, still too small.

But when I said "too small" i just had a look to my Dremel tool. I may cut my own cover to accomodate the 4x40 display.

I was also searching for some "notebook-sized" rigid plastic box. I found on Mouser this one that seems acceptable (not really on the cheap side) for my Cyprida project:
Its external size is 9.3" x 11.1" x 2.2", that is 236 x 281 x 56mm; I guess that the useful volume is 10mm less on every side. I did not choose a smaller one because I think I may accomodate one or two 5V batteries; I have two somewhat aged MobilePowerPack Li-Ion 5V batteries (USB-chargeable), 13 x 78 x 132mm.

Thursday, February 26, 2015

I need to emulate my own functions

Cyprida has 124 kb EEPROM space for code, way more than the 8 or 16 kb ROM of the home computers of the Legendary Eighties™, when Men were Men and had to fight with limited RAM resources and the twin monsters PEEK & POKE. Thus I will have limited RAM and will only need to implement some cryptic PEEKs & POKEs.

To test features without rewriting the EEPROM every time, I separated the actual Arduino-only code from the interpreter/editor code (which I can run on my PC). Now I have:

- cyprida.ino: sketch that will run on the ArduinoMega. Has a large setup() initializing everything, a library for the its peripherals, and a loop() that only calls emma() to start the interpreter/editor;

- cyprida.h: prototypes for the "emulable" functions (like "clear screen", "print a character", etc)

- ardlib.cpp: emulation of the Arduino functions ("clear screen" and so on): initializes the Linux terminal and then starts emma()

- emma.cpp: the actual environment-interpreter only depending on cyprida.h functions (it is included by both cyprida.ino and ardlib.cpp).


The Makefile builds both the Arduino sketch and an emma executable to test.


Tuesday, February 17, 2015

Bluetooth (via UARTSB-2.2) now works (sort of)

I'm fiddling with my remaining hardware drawer. It was about 2009-2010 when I bought an UART_SB 2.2 on SeeedStudio; don't know why I got it. A little later I bought a solderable Bluetooth Bee and practiced 2mm-pitched hand soldering with a 60 W soldering station!! Arrrgh.

Well, I now have this beast working either as a "USBserial to Bluetooth" adapter for the PC or "TTL serial to Bluetooth" adapter for the Arduino. I spent three entire evenings to figure out a working sequence, and finally was able to print on the LCD of the Arduino Mega a string sent via Bluetooth from Linux PC and getting an answer.


First, it requires a long initialization (ouch!) up to fourteen seconds at boot time before it can accept a connection (while everything other completes in less than 60 milliseconds).

I think this is due to an old firmware release of the soldered BluetoothBee unit. It does not answer "OK" to commands, but a rather clumsy "WORK:SLAVER". So I checked for a capitalized "K" instead of "OK" - it gets both "OK" and "ORK...".

So in my .ino source I wrote a function bluebee(char*) that:
  • waits 120msec
  • sends the command string with Serial3.print
  • reads any incoming characters
  • if a 'K' is received, then flush incoming characters in 30msec and return "OK"
  • if the function is running for more than 3.3 seconds, then call for "FAIL".
And then initialized it on the Arduino Mega using:
  delay(1000);                      // at boot: wait 1sec before sending commands
  bluebee("\r\n+STWMOD=0\r\n");     // 0: client (slave) mode
  bluebee("\r\n+STNA=MyArdu\r\n");  // set bluetooth hostname
  bluebee("\r\n+STAUTO=0\r\n");     // 0: disable "autoconnect last paired device"
  bluebee("\r\n+STOAUT=1\r\n");     // 1: enable paired device to connect
  bluebee("\r\n+STPIN=0000\r\n");   // set a pin to accept incoming connections
  delay(2000);                      // required pause after setting up the pin
  Serial3.print("\r\n+INQ=1\r\n");  // 1: enable inquiring
  delay(2000);                      // required pause after sending the INQ=1

Yes, the +INQ=1 command does not answer anything. Yes, those delays are quite tight, do not reduce them. Yes, I did not use the +STBD to setup baudrate because I was happy with the default 38400; you don't need ultra-turbo speeds to send a few characters at a time.

Connections: the TX3/RX3 of the ArduinoMega are connected to the RX/TX pins of the UARTSB (note the mini-dip-switches on "5V" and "Bluetooth"), while the +5V and GND are required on the USB plug side. I cut a miniUSB connector and soldered its red/black (+/-) cables to the 5V/GND pins of the Arduino Mega.

For debugging reasons, I added to the .ino source a loop to print on the LCD of the ArduinoMega the incoming characters of the Serial3 port.


Operation:
  • apply power to turn on the ArduinoMega
  • wait for its boot and bluetooth initialization
  • on the Linux PC bluetooth section, select "Setup (pair) a new device"
  • wait the name to appear in the device list (the above example uses "MyArdu")
  • choose a pin number to pair it (the above example uses 0000)
Yes, the UARTSB+BluetoothBee do not have "memory": on my PC I have to delete the pairing ad redo it again every time the ArduinoMega is rebooted.
If I forget to delete/redo the pairing, the cat /dev/rfcomm0 shown below will silently terminate in about 3.7 seconds because a rebooted BluetoothBee does not "remember" having paired with my PC.
Then release (if already assigned) and create the radiofreq communications channel /dev/rfcomm0 as a serial port (type 1). If you don't remember the fixed address of the BluetoothBee you can use the hcitool scan --flush command to find out after the initialization is completed (in the example below it is 00:18:E4:E5:E6:E7).

  hcitool scan --flush
  sudo rfcomm release 0; sleep 1 ; sudo rfcomm bind 0 00:18:E4:E5:E6:E7 1 

Now if I write something on /dev/rfcomm0 I get a bizarre "Transport endpoint is not connected" error. This is due to the BluetoothBee requiring some time to get a connection up and running.
Note that if you did neither pairing nor rfcomm bind but the /dev/rfcomm0 is still there, you may even get a "no error" on a write... but it will not reach the Arduino.
So I open a terminal window and start cat /dev/rfcomm0 and then in another terminal window I can write using echo ' #OMG it works! ' >/dev/rfcomm0
Trick explained: the cat /dev/rfcomm0 opens the port and stays there waiting for a line of characters. After some time (some five seconds), the BluetoothBee is ready to accept characters.
Note that the Arduino HardwareSerial library has a limited serial buffer - on the Mega it is only 64 characters. This means that if I try to write 70 characters at a time, the entire Bluetooth packet is received by the Bee, then sent to the HardwareSerial library of the Arduino Mega which fills immediately the 64 bytes buffer, losing the extra six characters. The Arduino should continuously consume incoming characters (while(Serial3.available()) { processthisbyte(Serial3.read()); ...) because the 64 bytes buffer will fill in some 16 milliseconds (at 38400 baud speed).

Note: Ubuntu 14.04 Bluetooth Settings has a bug in the "Bluetooth New Device Setup": it forgets the entered pin. So I need first to wait some 10 seconds that the BluetoothBee device appears in its list, then click on it, then click on Pin Options; then select "0000 [most headsets/GPS/etc]" and "Close" the dialog, then click again on the BluetoothBee device in the list, then select again "0000" (most of the times it was "Auto" again) and "Close", and then "Continue". It should not require to enter a six-digit pin...!

Note: when actually "connected", the BluetoothBee name is listed in bold characters in the Settings / Bluetooth window of the Unity Control Center.

Note: one I got you may try to use /dev/rfcomm1 if you think that rfcomm0 is stuck

Yes, this old BluetoothBee has its drawbacks but it works:
  • ArduinoMega has the UART_SB + BluetoothBee ready to accept a "secure" wireless serial channel ("secure" means that you use a non-trivial pin like 0000... but only setup it after you are sure that everything works with the default 0000), that I placed on the TX3/RX3 (because I don't want to fiddle with pins 0/1 TX/RX unless absolutely required); you may consider the SoftwareSerial if you don't have a Mega;
  • once established a connection, ArduinoMega can regularly read incoming characters using Serial.available and Serial3.read and then answer with Serial.write functions
  • on the PC side, it is required to pair again, then release/bind the port, and then open the connection and wait a little while before sending characters.
The above examples use cat and echo but once the serial wireless channel is established, I can work out multiple interrogations. I used a thread for a fake "open channel to read" (to emulate the cat) that gets killed as soon as the main task is "go": here is the rubytalkswitharduino.rb script:

#!/usr/bin/env ruby

fake = Thread.new do
  fpfake = File.open '/dev/rfcomm0'
  while true
    fpfake.gets
  end
end

ok = Thread.new do
  sleep 5
  fp = File.open '/dev/rfcomm0', 'w+'
  Thread.kill fake

  fp.puts " [Ruby: #{$$} OK] "
  puts "PID #{$$} talked; response:"
  puts fp.gets

  fp.puts " <#OMG: #{Time.now}> "
  while true
    print fp.read(1)
  end
end

ok.join

Note that the gets requires a newline (then Serial3.println on the Arduino side). Note also that the gets in the fake thread does not have to get actual data (it just has to stay there waiting for the rfchannel to warm-up). My ArduinoMega just answered to "OK" and "OMG" commands sending (Serial3.println) some text.

Below, the complete sequence script (note that the "sleep 30" was to be sure that some time passed after last "rfcomm release 0"):

sleep 30
sudo rfcomm bind 0 00:18:E4:E5:E6:E7 1
sleep 1
ruby ./rubytalkswitharduino.rb

Sunday, February 15, 2015

Direct 5V supply: just add a diode...

Arduino documentation states that you should not bypass its regulator to supply power - i.e.: don't supply 5V on the 5V pin.


I just read that you can bypass the onboard regulator - just add a diode from 5V (anode) to Vin (cathode) to avoid reverse driving the regulator; for example an 1N4001.

Current through a diode can only flow from the anode to the cathode. Usually diodes have a black or gray line near the cathode.

LEDs: "light emitting diodes":

Saturday, February 14, 2015

What about Arduino Due ?

Arduino Due is a 3.3V board having almost the same pin layout of the Arduino Mega.

Its ugliest drawback is that its input pins are not 5V-tolerant. If you "write" a logical 1 on a higher-rated voltage input pin, it will almost always work ("writing" 3.3V on a 5V input is safe because it is somewhat near 65-66% of the required voltage; I expect it to be catched as a logical 1 everytime; "getting" 5V on a 3.3V-rated input pin means that you probably just destroyed it - or the entire board).



Specifications are quite interesting:

- 96 kb RAM vs. 8 kb RAM: you can emulate a full "64k RAM" 8-bit era computer with 32k extra for the operating system;

- 84 MHz clocked SAM3 processor: you can emulate a full 8-bit era computer at native speed... or way faster;

- 512k flash memory: you can store not only the full emulation program, but also some "floppy disks / microdrive cartridges / tapes" as well;

- the 3.3V rail can supply 800mA current: you can add peripherals and even a small screen requiring up to 2.6 watts total.

Yes, if it had 5V-tolerant I/O pins, it would have been a great machine.

Thursday, February 12, 2015

Cyprida gets gigabytes

Arrrgh. I have slightly more than six kilobytes RAM available, and the smallest microSD card I found in my spare parts drawer is a 4Gib one, featuring 3.8 millions kilobytes free space.


The Arduino SD library uses 512 bytes of RAM to store an entire sector and some extra RAM; serial ports libraries and printf stuff also suck some memory: this is why the free RAM of the ATmega dropped from 8k to about 6600 bytes. I bet the largest block available should be a bit less than six kilobytes.

Current status:
  • 4x40 display: works, but I was unable to do anything more than 7-bit text. I tried to build custom characters but it just didn't work, even in the lower half display
  • piezo beeper: works
  • microSD: works
It's almost time to work out a keyboard.

Next step will be implementing some BASIC interpreter. Man, I hate BASIC, but now I can't figure anything better. A Forth interpreter is just lame; a Pascal interpreter seems useles; a C interpreter could be too complex. I also hate prehistoric stuff like COMIT, Algol, SNOBOL and exotic stuff like Logo, PL/M, REXX.

Well, I'll have to design my own interpreter and editor. It should have the same basic features of a common home-computer of the 80's: execute commands directly or after editing a program listing, easy to learn and use, integers, floats and strings operations, no baroque features, no Commodore PEEK/POKE-bloat.

Tuesday, February 10, 2015

Cyprida gets music


A while ago I bought a buzzer because I read the Arduino Tone tutorial. And now the buzzer is in. I soldered it below the shield to sack some of that unused physical space while hiding that ugly cylindrical chunk (above I placed a 180 ohm resistor, which should limit to some 27mA at 5V; the 180ohm is the only one reasonably near 100 ohm I found in my drawer). I soldered the resistor between the "+" of the buzzer and the pin 10 of the Arduino Mega (it is a PWM enabled one and it is in the zapped zone: I had to wipe out pins 8, 11, 12 and 13 of the dremeled microSD shield because the SPI pins on the Mega are 50, 51, 52 and 53).

I also found a nice project Arduino Music featuring up to six voices on an Arduino Mega. It would require six resistors (as current limiters), having a grand total "parallel resistors" value around 100-150 ohm (I should check how much current the output pins can source, and how much current the buzzer can handle); I bet that different values could get different voice levels. The drawback is that it requires up to all six ATmeg1280 timers and interrupt vectors. No, I don't want to fight with resistors and timers all at once; I'm not building a squarewave 6-voice music machine.

And finally I updated the firmware: a 100msec beep at boot time; 14.5k code space used, only to initialize screen, beep, serial ports and microSD. I wonder how much space I'll have for the actual firmware...

Sunday, February 8, 2015

Drrrremel!

It happened a number of times. Once while talking about cutting pie slices. Another while talking about a small hole. I accidentally used the term dremeling, making people around - mostly girls - asking me: "what?".

Today - a rainy Sunday - a bit of quick and dirty dremeling saved my day. Now I can start soldering some bits. Geez, I can't count the times I said how worthy were those 100+ bucks for a Dremel 4000 set.


Saturday, February 7, 2015

Planning a new contraption

A while ago I bought this Arduino microSD shield and quickly soldered the pins... and a microsecond later my project had to be scrapped.

Sadly, this nice shield uses pins 8,11,12,13, whereas the Mega uses the 50,51,52,53.


Either I de-solder the four pins out there, or I find another way to add a microSD to my Arduino Mega...

Friday, February 6, 2015

Arduino reset serial issue

Today's lesson: experimenting with some serial stuff (*) I saw Arduino Mega rebooting... Welcome to the Infamous Reset Issue. Gotta find a "120 ohm" resistor (that is: compose some resistors to get a value between 110 and 124 ohm).


More info on the Arduino Playground.

(*) it only was Serial3.begin(115200); Serial3.print("test");

Thursday, February 5, 2015

Murphy's Law about 4x40 LCD displays

Well, the 4x40 LCD display is sick - Murphy's law about a project states that while you move your first steps you find some devastating problem, enough to kill more the project value than the project feasibility.

I bought this "untested 4x40 LCD display, should work" at a HAM-fair in Pescara, Italy, some 7-8 years ago, "too cheap to not to buy". And now - only now - I understand why it was so dirt cheap.

It is a 40466 revision 2, based on HD44100FS and HD44780A00 chips (thus the Japanese font version). And now I also notice that manufacturing date on the right side: March 29, 1996.

And it has problems:


It has a number of hardware/software problems, most of all:

1) does not work correctly with any of the Arduino LiquidCrystal libraries (including Extended, 4x40, etc), many commands either do not work or just crash;

2) it has a large area (from the 3rd to the 34th character cell of the first two lines) that is not correctly drawn (apparently the vertical control lines are shifted). No, the font commands did not change the result.

So I began to write my own display driver from scratch using the HD44780 documentation.

After some experimenting I found a few reliably working bits:
- a screen initialization sequence
- the "move cursor" instruction
- the "print a character" instruction
- the "show/dontshow cursor" function.

This is sufficient to make it work. For example, I had to implement a clear screen function moving cursors to home and printing 80 blank spaces, because the LCD clear screen command does not work. I had to implement a memory map and a "known last cursor position" thing as well. But -hey!- it now works, including backspace, tab, scroll, and a single flashing cursor (yes, normaly it shows two cursors! 4x40 displays are actually two 4x20 in a single case).

A minimal Hello World program only requires 1676 bytes of flash space.

Monday, February 2, 2015

Why Arduino Mega?

I have a spare Arduino Mega 1280. I bought it years ago, only to complete my collection of Arduino boards. I started the current project only to have it doing more than blinking a LED. And I found some interesting features.

First, it has lots of directly addressable pins... grouped together. For example, to set to "high" the pins marked "analog pins 0 to 7" as GPIO (digital pins), it is sufficient a single instruction:
PORTF = 0xff;
It is also convenient for setting more than one pin in a single instruction:
PORTF &= 0x3c;
More info on Port Manipulation.


Summary on the Arduino Mega boards (1280 and 2560):
  • PORTF: 8 in-line pins, west side ("analog pins 0 to 7")
  • PORTK: 8 in-line pins, west side ("analog pins 8 to 15")
  • PORTA: 8 pins (two adjacent rows of 4 pins), south side ("digital pins 22 to 29")
  • PORTC: 8 pins (two adjacent rows of 4 pins), south side ("digital pins 30 to 37")
  • PORTL: 8 pins (two adjacent rows of 4 pins), south side ("digital pins 42 to 49")
  • note also the blocks of 4 adjacent pins for PORTB, PORTH, PORTD.
If you don't need analog pins, you can fully use PORTF and PORTK to read/write up to eight pins at a time.

If you don't need external RAM/SRAM, you can fully use PORTA and PORTC.

If you don't use weird things like external interrupts, you can fully use PORTL.

Yeah, five blocks of 8 pins each. Things like:
if(PINK) call_a_function();
"if any input pin of PORTK is on level high, then call a function".

Just forget the digitalRead/digitalWrite stuff.

Just don't forget to assign the appropriate data direction register in the setup() phase.
DDRF = 0xff;    // declare eight output pins
PORTF = 0x1f;   // output 3 low and 5 high pins

Sunday, February 1, 2015

Many pins, easy keyboard

Having many I/O pins directly addressable means that you can immediately scan a keyboard.

Example: an intercom numeric keyboard, 4 rows by 4 columns (16 keys total):


it has 8 pins (4 for rows, 4 for columns): when you press a key, their respective pins are shorted.



Imagine you have those 8 pins on a single port of the Arduino, for example PORTC and its data direction register DDRC. You don't have to use digitalRead, you just read and write PORTC value, sending '1' to all columns to check if any row has changed, and vice-versa. For example:

int keypressed()
{
  // start with first scan: high bits (columns)
  DDRC  = B11110000;
  PORTC = B11110000;
  int c = PINC & B00001111;
  if(c == 0) return 0;  // return if "no key pressed"

  // a key was pressed, and now we know the columns
  // now: second scan: low bits (rows)
  DDRC  = B00001111;
  PORTC = B00001111;
  int r = PINC & 0xf0;
  if(r == 0) return -1;  // return "unknown" if key was released before this point

  switch(c | r)
  {
    case B10001000: return '1';
    case B10000100: return '2';
    case B10000010: return '3';
    case B10000001: return '4';
    case B01001000: return '5';
    case B01000100: return '6';
    case B01000010: return '7';
    case B01000001: return '8';
    case B00101000: return '9';
    case B00100100: return '0';
    case B00100010: return 'z';   // "lamp" key
    case B00100001: return 'u';   // "phone" key
    case B00011000: return '#';
    case B00010100: return '*';
    case B00010010: return 'k';   // "key" key
    case B00010001: return '\n';  // "return" key
  }

  return -1;  // return "unknown" if more than one key pressed
}


Code needs a bit of extra to check for key-released event and bouncing; it may be easily optimized using a look-up table, and some extra code could identify combinations of keys (e.g. for things like "shift-" or "ctrl-").