0

Back to golf

Posted by Chris on Friday, July 31, 2009 in , , , , ,
Well actually, back to the more generic type of game scoring device. While RobotSteve gets on with making some rather smashing looking servo controller boards I've been coding yet more for the golf device.

To date we've got
  • eeprom driven menus
  • up to 4 player support
  • Edit player names
  • Edit player parameters (handicap and golf tees)
  • eeprom driven bitmaps
  • Nokia-type joystick support
.
Something to look out for with these Nokia breakout boards is running them at under-voltage.
I left my PP3 (9v) battery connected to the display all night and in the morning the battery was only giving out 7v. This meant - and I've yet to work out why - that only 4.3v was coming out of the voltage regulator, instead of the full 5v (not very regulated then!).
At this voltage, the Nokia screen (which usually requires 5v to drive it) would reset intermittently. This would sometimes also cause the pic micro to reset too. So behaviour was very unpredictable. Also, because of the lower supply voltage, the joystick values did not read true, and the logic to decide which button was pressed did not always work either (with the effect that the menu selector would appear to pick random entries from the list, instead of the one immediately above/below the highlighted entry).

Below is a video showing Nokia development so far.
It shows how eeprom-driven menus can move control onto a new screen (screen refreshing is slow because we're reading bitmap bytes from eeprom at just 400khz, not a the full 20Mhz that the chip can run at) and also how to edit player details.

Once perfected, these techniques can be used as the basis for other game scoring devices - after all, most games involve picking one or more players, entering their names, and providing some extra information (such as handicap/tee preference in golf, maybe boule weight or team position - pointer, shooter, middle - for petanque and so on).

0

USB servo controller

Posted by Chris on Monday, July 27, 2009 in , , ,
In a break from all the golf coding of recent weeks, a previous project made a welcome reappearance this week - the multiple usb servo controller. Welcome in that it gave us an opportunity to actually complete something and get that warm fuzzy feeling that so often accompanies putting a project to bed!



The hardware development is complete. Data can be sent to the device using a USB connection, and is as easy as copy-and-pasting a list of bytes from the online editor. Below is a video of the test app used to send data to the servo controller board eeprom. You can see the data values and see them being played back in the video above:



A new version of the editor is currently in progress and when complete can be found, along with a whole host of support materials, at www.botbuilder.co.uk.

0

Online golf course editor

Posted by Chris on Wednesday, July 22, 2009 in , , ,
Work is almost complete on the online golf course editor.
Below is the link to a preview version of the editor.
http://www.scoresure.co.uk/golf/coursedetails.asp?courseid=ABCDEFG&holeno=1

Meanwhile, the first golf-oriented menu and bitmap has found its way onto the Nokia screen. Here is the main menu for Score Sure Golf Pro:


0

Golf goes online

Posted by Chris on Monday, July 20, 2009 in , ,
Work on the Nokia 6610 display and joystick continues at quite a pace and with the eeprom-drive menu code complete, it's time to get down to the nitty gritty of actually (re)building our ScoreSure Golf Pro digital scorecard device.

One of the planned features of the device is to download golf course data from the website www.scoresure.co.uk. This means putting it up there in the first place! Which means not only an online editor, but some method of recalling and displaying the golf course information - Adobe Flash seemed a perfect choice for this, and it is anticipated that the golf part of the website will be a mixture of HTML/XML/Ajax/Javascript and Flash.

http://www.scoresure.co.uk/golf/coursedetails.asp?courseid=ABCDEFG&holeno=1

The golf course hole information has been recreated using the course guide booklet and scorecards, available from the golf shop and online.


0

Joysticks rule

Posted by Chris on Friday, July 17, 2009 in , , ,
...especially when they're attached to a Nokia 6610 breakout board. This little fella provides 4-axis input (plus a "fire" button) using a single input pin. It's quite clever really, but simply uses a load of resistors, to change the input voltage depending upon which direction has been pressed.
Put the input from the miniature joystick on the Arduino Nokia board onto pin A0 of a PIC microcontroller and read the input values.



The Oshonsoft PIC18 the command for reading an analogue input is:
Adcin 0, joystickvalue


This takes the input from analogue channel zero (in our case, PORTA.0) and writes it to the variable "joystickvalue".
During testing, with an open connection (joystick centred, no movements made) the joystick value wavered between 169-170. At first this seems odd, but looking at the schematic datasheet we can see that the reference voltage from the joystick is between 0v and 3.3v.

Taking the average value of 170, and given that we're storing this data into a byte variable, we can see that (170/255)*5v = 3.3v.
So it all makes sense again - with no joystick movement, we expect to receive 3.3v from the joystick onto our analogue pin. And the value 170 does indeed represent a 3.3v signal when our PIC is powered by a 5v supply.

A simple routine was put together to write the value of the joystick input onto the Nokia screen. The following was determined:



This translates quite nicely into a simple subroutine for any project that uses this board. The routine waits for the joystick to be moved, stores the direction into a variable then waits for the joystick to be released again.
The routine can be called from anywhere in the program, though it might work quite nicely if called from a timer interrupt, since the user input is stored until the microcontroller is free to process it.


Dim joystickvalue as Byte
Dim jstick(5) as Byte
Dim buttonpressed As Byte

jstick(1) = 126 'right
jstick(2) = 88 'up
jstick(3) = 60 'down
jstick(4) = 26 'fire
jstick(5) = 4 'left



getbuttonpress:
  'single input ADC for joystick press
  Adcin 0, joystickvalue

  'compare current joystick value to stored values
  'at rest returns 172-168, first value is 120-122 for "right"

  If joystickvalue < 140 Then
    For i = 0 To 4
      If joystickvalue < jstick(i) Then
        buttonpressed = i
      Endif
    Next i

    'debounce the button press
    WaitMs 1
    Adcin 0, joystickvalue
    If joystickvalue < 140 Then
      'wait for the button to be released
      While joystickvalue < 140
        'keep sampling the joystick to see whether it's been released
        Adcin 0, joystickvalue
      Wend
    Else
      buttonpressed = 0
    Endif

  Else
    buttonpressed = 0
  Endif

Return



0

More on menus

Posted by Chris on Thursday, July 16, 2009 in , , ,
One thing that quickly comes to light when working with the Nokia 6610 display - it has no libraries of its own to use: that means that you have to hand-code pretty much everything for it, including making your own fonts and writing your own bitmap display routines.
This means that your code bloats up pretty quickly.

In fact, to demonstrate using bitmaps, drawing strings of text, and including USB support (in order to send commands to the display to test different combinations of things) our code is already a whopping 9.4kb in size.
That leaves around 15kb of space for actually coding that the device should do (on a 18F2455 chip anyway). So almost half of the available program space is taken up with libraries for controlling the display! (ok, it also includes a routine for reading/writing to eeprom, but that it itself is only a few hundred bytes big!)

In fact, forgetting about the eeprom routines could be quite a mistake - instead of hard-coding menu data into the program memory (which strings to display and in which order) it makes a lot of sense to put these strings into external memory.
This offers two distinct advantages: firstly, you're not filling all your program space with strings of characters that make up the menus (you can just use a double-byte word to keep track of the eeprom address that contains the string to draw for each menu item). Secondly, it means porting your device to another language (it's wishful thinking, but there's a massive European market for electronic golf scorecards too) is a relatively painless task: simply update the strings held in eeprom using an external app and your original device code does not need to keep being amended and recompiled. Interesting idea....

Taking this idea a step further, instead of just storing strings in memory, I've decided to store the entire menu structure in eeprom.
The block diagram looks something like this:



  • Each menu begins with a title
  • C = count the number of items in this menu
  • X/Y = position on screen this menu should be displayed at
  • goto = pointer to eeprom address of the next menu to be displayed

The "variable" C has two functions:
The upper three bits are flags to tell us:
  • Clear the entire screen before drawing this menu?
  • Remove this menu after selecting an item?
  • (reserved)

The remaining lower bits contain the value (1-31) telling us the number of items in the list.

The variable "goto" has some special/reserved values:
0 = do nothing when any item in this menu is selected
65535 (0xffff) = go into edit mode when any item in this menu is selected

"Edit mode" puts the device into a special state, where each character of the menu item can be highlighted and changed, individually. This means that, for example, player names can be put into a menu (so that a player can be selected) but at the same time, player details can be updated (e.g. change the letters of a players name).

If the variable "goto" has a valid value (i.e. a number between 1-65534) then this is the eeprom memory address containing the next menu. The current menu is cleared from screen (if necessary) and the new menu is drawn.

Here's a sample menu, converted to a byte array and written to eeprom
84, 105, 116, 108, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 12, 20, 77, 101, 110, 117, 32, 105, 116, 101, 109, 32, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 77, 101, 110, 117, 32, 105, 116, 101, 109, 32, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 77, 101, 110, 117, 32, 105, 116, 101, 109, 32, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 77, 101, 110, 117, 32, 105, 116, 101, 109, 32, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0

You'll see how the first byte is 84 (ascii 84=letter T), followed by 105 (ascii 105=i) and so on, spelling out the word "Title" and some padding bytes. The values 4,12,20 are the C,X and Y values, followed by the next line item in the menu: ascii 77=letter M, ascii 101=letter e (and so on, spelling out "Menu item 1").
Here's the resulting menu, drawn on the Nokia 6610 screen:


0

Nokia 6610 menus

Posted by Chris on Thursday, July 16, 2009 in , , ,
There have been some exciting developments with our Score Sure Golf Pro game scoring device recently: namely that we've managed to get a full-colour Nokia 6610 128x128 display working with a PIC18F2455!

What does that mean?
For our ScoreSure range of devices, it means the hunt for a stable, decent screen is finally over! It also means the whole thing will fit into a much smaller enclosure, making it much more "pocket-friendly" and therefore more likely to gain acceptance. There were concerns, after seeing the original device actually working on a 128x64 mono glcd, that it might be getting a bit big and bulky. Of course, it also means we now how a full-colour display (although it'll still mainly be used as a mono device, due to memory/storage constraints!) but the odd splash of colour here and there won't go amiss!

It also means that there's now a library of PIC-based functions available for drawing bitmaps, writing text/displaying fonts AND creating menus. Readers of earlier posts will see that we've already had monochrome bitmaps displayed - the bug that stopped rending the image properly came from the VB app used to convert the image into a sequence of bytes and NOT the PIC rendering code (so the list of bytes you see in that example cause a white line to appear under the golfers feet).



Using the work done with an earlier GLCD the Nokia 6610 can also display strings of text. Unlike mono GLCD displays, where a vertical "slice" of 8 pixels for each character is sent in a single byte, the Nokia 6610 uses a single byte PER pixel. So that means breaking each character down into 5 vertical slices, then looping through each byte, and checking the status of each bit in the byte.
If the bit is set, the value for the "foreground" colour is sent - if the bit is not set or zero, the value for the background colour is sent to the display.
Thus strings of text are always drawn inside a box and you need to match the box background colour with the background colour of the display to avoid having big stripes of colour all over the screen.

To make our display more readable on the Nokia 6610, the fonts have been redesigned. Each is still 5x8 pixels, but this time a single pixel spacing remains at the bottom of each character. The character height has also increased by a pixel.
Below is a screenshot of how the characters were drawn using a homemade VB app to convert pixels into byte-slices:



The fact that strings are drawn inside boxes can be exploited for drawing menus.
By setting the background colour to one different to the colour of the display, when a string of text is drawn, it appears to be inside a coloured box. It is easy to imagine that a simple "if" statement can be used when rendering a menu to decide whether to use the default background colour (black/white) or the highlight colour (red) when drawing a string of text on the screen.
When the menu bar needs to be moved, the string of text that is highlighted is simply drawn again, this time using the default background colour.

The characters were redrawn and deliberately centred vertically inside each 5x8 grid (as best could be achieved) so that when drawn using a different background colour, they did not appear off-centre.

Here's a screenshot of the output acheived using these fonts:


0

Monochrome bitmaps on a full colour display?

Posted by Chris on Sunday, July 12, 2009 in , , , , ,
The Nokia 6610 display can support up to 12-bit colour so why bother with monochrome bitmaps?

Well, using a PIC microcontroller, even with 24C256 I2C eeprom (256kb) attached, doesn't provide a massive amount of memory for displaying full colour bitmaps. Even a simple 256 colour image (8-bit palette, similar to a GIF) uses one byte per pixel (the Nokia supports modes that use up to 2-bytes per pixel). The display is 131x131 (often listed as 128 by 128 but this allows for non-viewable pixels around the edge of the display) so a GIF-type image would take a whopping 17,161 bytes (around 16kb).
Given that the PIC18F2455 has 24kb of program space (it was tempting to write "only 24kb" but that's doing the chip a disservice!) coding a single full-colour image uses up 3/4 of the available space. Add in USB support, using the Oshonsoft PIC18 compiler and you've filled the program memory without actually writing any of your own code!
Also, dragging data back from the eeprom chip inbetween drawing pixels on the screen means that displaying the full colour image actually takes quite a long time.

Compare this to a displaying a monochrome bitmap.
First off, pixel data can be packed into packets of 8-bits - since each pixel takes on the colour of either "foreground" or "background" (a one or a zero can be used to represent either state). This means that a full screen image takes up (131 x 131)/8 = 2,146 bytes.
For images that have large areas of the same colour, the "bitmap" data could be written as "number of pixels before pixel changes colour". This can reduce the amount of memory used quite drastically.

Below is a screenshot of a VB app thrown together which loads a monochrome bitmap image and outputs two byte arrays - one an array of pixel data using 1=foreground colour, 0=background colour, the other an array listing the number of pixels in a (vertical) row before the pixel colour changes:



The image loaded was 43x87 pixels.
This can be represented as (43x88)/8 = 473 bytes.
(the image size has to be rounded up to 88 so that it is a multiple of 8, allowing the data to be packed into byte-sized packets).

Below is the byte array used to store the golfer bitmap data:
0x00, 0x00, 0x00, 0xE0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xF0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x98, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x8C, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0xE0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xBF, 0x00, 0xF0, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0xF8, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0x00, 0xF8, 0x7F, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x00, 0xF8, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x9F, 0x00, 0xF0, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x83, 0x00, 0xF0, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x81, 0x00, 0xD8, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x81, 0x00, 0x0C, 0xFC, 0xFF, 0x03, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x80, 0x00, 0x06, 0xF8, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0xFC, 0x7F, 0x80, 0x00, 0x03, 0xF8, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0xFE, 0x3F, 0x80, 0x80, 0x01, 0xFC, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x0F, 0x80, 0xC0, 0x00, 0xFE, 0xFF, 0xFF, 0x03, 0x00, 0xE0, 0xFF, 0x0F, 0x80, 0x60, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x80, 0x38, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x80, 0x7C, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0xA0, 0x7E, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0xF0, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0xF8, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3E, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xC3, 0x7F, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0xFC, 0xFF, 0x3F, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x9F, 0xF8, 0xFF, 0x1F, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x8F, 0x80, 0xFF, 0x0F, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0xFE, 0x07, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x80, 0x00, 0xF8, 0x01, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x80, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x7F, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x03, 0x00, 0x00, 0x00, 0x80


But changing the method of recording data as "number of same coloured pixels" can be recorded as
29, 5, 53, 1, 28, 6, 53, 1, 27, 2, 2, 4, 52, 1, 26, 2, 3, 3, 53, 1, 25, 2, 5, 1, 54, 1, 24, 2, 61, 1, 23, 2, 62, 1, 22, 2, 63, 1, 21, 2, 64, 1, 20, 2, 65, 1, 16, 5, 66, 1, 14, 6, 67, 1, 13, 7, 59, 7, 1, 1, 12, 9, 54, 13, 11, 11, 52, 14, 11, 12, 2, 2, 46, 15, 11, 18, 44, 12, 2, 1, 12, 18, 41, 11, 5, 1, 12, 19, 39, 11, 6, 1, 11, 2, 1, 18, 36, 13, 6, 1, 10, 2, 6, 16, 33, 13, 7, 1, 9, 2, 8, 17, 30, 13, 8, 1, 8, 2, 9, 18, 28, 13, 9, 1, 7, 2, 9, 22, 24, 12, 11, 1, 6, 2, 9, 25, 19, 15, 11, 1, 5, 2, 9, 58, 13, 1, 3, 3, 8, 58, 15, 1, 2, 5, 6, 58, 14, 1, 1, 1, 1, 6, 4, 58, 15, 4, 1, 67, 15, 5, 1, 65, 16, 70, 3, 34, 1, 74, 1, 5, 8, 74, 1, 9, 4, 9, 2, 61, 1, 1, 2, 20, 5, 58, 2, 1, 3, 18, 7, 56, 3, 1, 7, 13, 11, 49, 7, 1, 9, 10, 14, 45, 9, 1, 11, 6, 17, 39, 14, 1, 36, 30, 21, 1, 41, 14, 32, 1, 44, 6, 37


This uses just 231 bytes to store the entire image.
And here it is drawn back on the Nokia display (code includes a yet-to-be-resolved bug, but you can see the bitmap image displayed clearly on the LCD).



So why use monochrome images when you have a full-colour display?
When working with PIC microcontrollers or limited memory space, because you can get an image size down from a ridiculous 16kb down to just 231!

0

It's one small step for (a) man.....

Posted by Chris on Friday, July 10, 2009 in , , ,
....one giant leap for Nokia 6610 colour LCD display boards!
Armed with little more than a Phillips PCF8833 datasheet and some Arduino code libraries, excitement reigned around Nerd Towers today, as this little colour LCD Arduino shield flickered into life.

The screen uses SPI to send byte commands to the screen.
After initialising the screen, data is written using the following format:

First a "window" is defined, by providing start-x, end-x, start-y and end-y co-ordinates (0-131). Then, a stream of data is sent, with (in 8-bit mode) each byte representing a pixel colour.
You can define how the screen behaves after each pixel-byte is received. I set my display up to draw pixels from top-to-bottom. When the current pixel reaches the bottom of the defined window size, it increases the column counter and returns to the top of the window



Unlike most serially-driven devices, the Nokia 6610 display uses 9-bits NOT 8 to transfer data to the screen. The first bit tells the display whether the following byte is a command (first bit is zero) or some data (first bit is set).

Although Oshonsoft includes built-in software driven SPI routines, I decided to write my own (using the ones in the Arduino library as a base) which send 9-bits in a continuous stream. Because Oshonsoft Basic is so simple to understand, this implementation could be easily ported to a compiler of your choice. The full code listing follows. Below is a summary of how to use the device:

Creating a window:
Put the display into "command mode" (set the first bit of the stream of 9)
Send the command bit followed by 0x2A (command to set the column/x co-ord)
Put the display into "data mode" (clear the first bit of the next stream of 9)
Send the x-start value as a byte (0-131)
Send the x-end value as a byte (0-131, must be greater than x-start)

Put the display into "command mode" (set the first bit of the stream of 9)
Send the command bit followed by 0x2B (command to set the column/y co-ord)
Put the display into "data mode" (clear the first bit of the next stream of 9)
Send the y-start value as a byte (0-131)
Send the y-end value as a byte (0-131, must be greater than y-start)

Put the display into "command mode" (set the first bit of the stream of 9)
Send the command bit followed by 0x2C (command to start writing pixel data)
Put the display into "data mode" (clear the first bit of the next stream of 9)
Send each pixel colour as a byte (assuming 8-bit colour mode)
Repeat for each pixel in the window

Here's the full code for a working PIC project:

Define CLOCK_FREQUENCY = 20
Define CONFIG1L = 0x24
Define CONFIG1H = 0x0c
Define CONFIG2L = 0x3e
Define CONFIG2H = 0x00
Define CONFIG3L = 0x00
Define CONFIG3H = 0x83
Define CONFIG4L = 0x80
Define CONFIG4H = 0x00
Define CONFIG5L = 0x0f
Define CONFIG5H = 0xc0
Define CONFIG6L = 0x0f
Define CONFIG6H = 0xe0
Define CONFIG7L = 0x0f
Define CONFIG7H = 0x40

UsbSetVendorId 0x1221
UsbSetProductId 0x1003
UsbSetVersionNumber 0x1122
UsbSetManufacturerString "www.nerdclub.co.uk"
UsbSetProductString "Usb-to-SPI device"
UsbSetSerialNumberString "1111111111"
UsbOnIoInGosub usbonioin
UsbOnIoOutGosub usbonioout
UsbOnFtInGosub usbonftin
UsbOnFtOutGosub usbonftout

AllDigital

Symbol glcd_bl = PORTB.5
Symbol glcd_rst = PORTB.4
Symbol glcd_cs = PORTB.3
Symbol glcd_sda = PORTB.2
Symbol glcd_miso = PORTB.1
Symbol glcd_sck = PORTB.0
Symbol led = PORTA.0

Define SPI_SCK_REG = PORTB 'defines the port where sck line is connected To
Define SPI_SCK_BIT = 0 'defines the pin where sck line is connected To
Define SPI_SDO_REG = PORTB 'defines the port where sdo line is connected To
Define SPI_SDO_BIT = 1 'defines the pin where sdo line is connected To
Define SPI_SDI_REG = PORTB 'defines the port where sdi line is connected To
Define SPI_SDI_BIT = 2 'defines the pin where sdi line is connected To
Define SPI_CS_REG = PORTB 'defines the port where cs line is connected To
Define SPI_CS_BIT = 3 'defines the pin where cs line is connected To

'SDO is not used - but is mapped to MISO on the display
'(serial data out on the MCU to serial data out on the lcd)

Dim spibyte As Byte 'a byte to send to the lcd
Dim spibit As Bit 'first bit is 0=command, 1=data
Dim spiclockdelay As Byte 'how long to wait between spi clock pulses
Dim spiclockus As Bit 'whether clock pulse delay is us or ms

Dim xs As Byte 'x co-ord to start bitmap from
Dim ys As Byte 'y co-ord to start bitmap from
Dim xe As Byte 'x co-ord to draw up to
Dim ye As Byte 'y co-ord to draw up to

Dim i As Byte '}
Dim j As Byte '} general variables
Dim k As Byte '}


init:
  spiclockus = 1
  spiclockdelay = 4
  
  'drive an LED high so we can see what's going on
  High led
  Gosub lcdinitialise

  'drive the led low
  Low led

  UsbStart
  UsbService

loop:
  UsbService
Goto loop

End


sendspi9bits:

  '--------------------------------------------------------
  'FROM THE NOKIA DATASHEET
  'the serial interface is
  'initialized when SCE is High. In this state, SCLK pulses
  'have no effect And no power is consumed by the serial
  'interface. A falling edge On pin sce enables the serial
  'interface And indicates the start of data transmission.
  '--------------------------------------------------------

  'flash the led high
  High led

  Low glcd_sda

  'drive the cs low
  Low glcd_cs
  Gosub spidelay

  'first send the init bit, for either command or data
  If spibit = 1 Then High glcd_sda Else Low glcd_sda
  Gosub toggleclockpin

  'now clock 8 bits from the spibyte value starting with bit 7
  If spibyte.7 = 1 Then High glcd_sda Else Low glcd_sda
  Gosub toggleclockpin

  If spibyte.6 = 1 Then High glcd_sda Else Low glcd_sda
  Gosub toggleclockpin

  If spibyte.5 = 1 Then High glcd_sda Else Low glcd_sda
  Gosub toggleclockpin

  If spibyte.4 = 1 Then High glcd_sda Else Low glcd_sda
  Gosub toggleclockpin

  If spibyte.3 = 1 Then High glcd_sda Else Low glcd_sda
  Gosub toggleclockpin

  If spibyte.2 = 1 Then High glcd_sda Else Low glcd_sda
  Gosub toggleclockpin

  If spibyte.1 = 1 Then High glcd_sda Else Low glcd_sda
  Gosub toggleclockpin

  If spibyte.0 = 1 Then High glcd_sda Else Low glcd_sda
  Gosub toggleclockpin

  'bring cs high to indicate end of transmission
  High glcd_cs
  Gosub spidelay

  'flash the led off
  Low led
Return


toggleclockpin:
  'take the clock pin high, wait a second, drive it low
  Gosub spidelay
  Low glcd_sck
  Gosub spidelay
  High glcd_sck
Return


spidelay:
  If spiclockus = 1 Then
    WaitUs spiclockdelay
  Else
    WaitMs spiclockdelay
  Endif
Return


lcdinitialise:
  'this is taken from teh pcf8833.c file: Arduino library

  'turn on the backlight
  High glcd_bl
  WaitMs 1

  'send a dummy data byte
  spibyte = 0 'all zeros is interpreted as NOP in the display chip
  Gosub sendcommand

  'send software reset command
  spibyte = 0x01
  Gosub sendcommand
  WaitMs 10

  spibyte = 0x11 'sleepout
  Gosub sendcommand

  spibyte = 0x36 'memory access control
  Gosub sendcommand

  'when a bitmap is drawn to screen, you give a start x, start y
  'and end x and end y co-ordinate. Then drawing can go from left-to-right,
  'up-and-down, or up-and-down, wrapping round to move the pixel left-to-right.
  'For our fonts and so on, we draw each pixel top to bottom, then
  'when we get to the bottom of the column of data, move left to right
  'This is called vertical addressing mode.

  spibyte = 0xe0 'memory access options:
  '1 - my mx v lao rgb x x x
  'my=mirror in Y, mx=mirror in x, V=vertical addressing,
  'lao=line address order, rgb= colour order rgb/bgr
  'e0 came from the Arduino library and is 11100000b
  
  Gosub senddata 'note: data, not command

  spibyte = 0x25 'set contrast
  Gosub sendcommand

  spibyte = 0x40 'contrast value
  Gosub senddata 'note: data=contrast value, not a command!

  WaitMs 10 'allow things to stablise

  spibyte = 0x3a 'set colour mode
  Gosub sendcommand

  spibyte = 0x02 'xxxxx010 = 8-bit colour
  Gosub senddata 'note: data=colour mode value, not a command

  spibyte = 0x00 'dummy command - dunno why, but it's in the C library!
  Gosub sendcommand

  Gosub clearscreen
Return


createwindow:
  spibyte = 0x2a 'set x start and end co-ordinates
  Gosub sendcommand
  
  spibyte = xs
  Gosub senddata

  spibyte = xe
  Gosub senddata

  spibyte = 0x2b 'set y start and end co-ordinates
  Gosub sendcommand
  
  spibyte = ys
  Gosub senddata

  spibyte = ye
  Gosub senddata

Return


clearscreen:

  'turn off the display while the screen is cleared
  spibyte = 0x28
  Gosub sendcommand

  'create a rectangle area the size of the window
  xs = 0
  xe = 131
  ys = 0
  ye = 131
  Gosub createwindow

  'put the display into "write mode"
  spibyte = 0x2c
  Gosub sendcommand

  'fill the rectangle with black pixels
  spibyte = 0x00
  For i = 0 To 131
    For j = 0 To 131
      Gosub senddata
    Next j
  Next i

  spibyte = 0x29 'display on?
  Gosub sendcommand

Return


sendcommand:
  spibit = 0
  Gosub sendspi9bits
Return


senddata:
  spibit = 1
  Gosub sendspi9bits
Return


usbonftin:

Return


usbonftout:

Return


usbonioout:
  'we've received some data on the data i/o (from PC to device)
  i = UsbIoBuffer(0)
  Select Case i
    Case 1 'this is the token to say "send byte"
    If UsbIoBuffer(1) = 1 Then spibit = 1 Else spibit = 0
    spibyte = UsbIoBuffer(2)
    Gosub sendspi9bits


    Case 2 'this is the token to say "set delay time/length"
    If UsbIoBuffer(1) = 1 Then spiclockus = 1 Else spiclockus = 0
    spiclockdelay = UsbIoBuffer(2)

    
    Case 3 'this is the token to say "run the init sequence"
    Gosub lcdinitialise


    Case 4 'this is the token to say "draw a window"
    xs = 10
    xe = 60
    ys = 10
    ys = 60
    Gosub createwindow

    For i = 0 To 20
      For j = 0 To 20
        spibyte = 0
        spibit = 1 '1=data, 0=command
        Gosub sendspi9bits
      Next j
    Next i


    Case 5 'this is the backlight token
    If UsbIoBuffer(1) = 1 Then High glcd_bl Else Low glcd_bl


  EndSelect
Return


usbonioin:
  'we've received an io/data request from the PC (usbioin = send to PC)
  'for some data from the device.
  
Return





Once again, a big thanks to Robot Steve for lending me his Arduino kit while I try to source one of my own!

0

From drawing board to reality

Posted by Chris on Tuesday, July 07, 2009 in ,
Things are moving pretty quickly at Nerd Towers, with our Score Sure Golf Pro gaming device finally making it off the screen and onto the hardware!
Here's a picture of the device in development:



It's not entirely complete: there's something funny going on with the display. When a few characters are displayed, the contrast is nice and sharp and each pixel stands out clearly. As more pixels are lit up, the contrast gets dimmer and dimmer. To the point where if you try to display a bitmap image, the screen appears blank - and only by waving it about do you realise that the image is there, it's just that the contrast is so low, the pixels don't appear to be lit up.
Even during "normal" operation, where rows of text are sent to the screen, pale stripes appear everywhere, where the contrast for an entire column is lower than other parts of the screen.

Perhaps it's because it's one of these low voltage 3v ones.
Maybe there's a reason why most LCDs run off 5v.....

0

It works! It works!

Posted by Chris on Thursday, July 02, 2009 in , , ,
Victory at last!
Well, not quite, but at least I'm part-way there now!
Yet another GLCD arrived in the post this morning and as soon as I'd shredded it from it's bubble-wrapped envelope, I had a series of pins soldered on to it and had it connected up to my breadboard.

This time it's a LM6038B from Mainline.
A quick read through the datasheet and it looks ok: it's a ribbon-based display ready-mounted on a PCB, with all the nasty charge-pump capacitors and all that nonsense already in place. So you can just shove 3v onto the power/lcd pins and the backlight shares a 0v pin with the display controller, so only one ground connection needed!
The display supports the usual 6800 and 8080 parallel interface, as well as a serial interface. Great. But then I came across this in the datasheet:

1.5 Jumper functions
JP1JP2JP3JP4Interfacemode
closeopencloseclose6800 mode
openclosecloseclose8080 mode
opencloseopencloseserial mode (default)


That's right. Serial mode by default.
The jumpers are actually little solder blobs on the back of the display, so in theory they can be changed. Given that I'd been told that this display used a KS0108-compatible library, it was tempting to give it a go.
But then, I thought rather than screw up yet another display and get no further on, it might be fun/torture to get this working as-is, using the serial interface.

Here's the datasheet
Here's the Oshonsoft PIC18 Basic code to get an 18F2455 mirochip working with the display using PORTA and SPI communication. Simply wire up the microchip pins to the corresponding pins on the display. The only thing to look out for is SPI_SDO - I set this to a pin on PORTB as it's not used for this example - data is sent to the display, not read back from it. Any way, here it is:


AllDigital
'Config PORTA = Output

Symbol glcd_cs1 = PORTA.0
Symbol glcd_res = PORTA.1
Symbol glcd_a0 = PORTA.2
Symbol glcd_sclk = PORTA.3
Symbol glcd_si = PORTA.4

Define SPI_SCK_REG = PORTA 'defines the port where sck line is connected To
Define SPI_SCK_BIT = 3 'defines the pin where sck line is connected To
Define SPI_SDI_REG = PORTA 'defines the port where sdi line is connected To
Define SPI_SDI_BIT = 4 'defines the pin where sdi line is connected To
Define SPI_SDO_REG = PORTB 'defines the port where sdo line is connected To
Define SPI_SDO_BIT = 4 'defines the pin where sdo line is connected To
Define SPI_CS_REG = PORTA 'defines the port where cs line is connected To
Define SPI_CS_BIT = 0 'defines the pin where cs line is connected To

Dim glcdbyte As Byte 'the byte to send to the display
Dim glcdline As Byte 'used to set the current line number of the display
Dim i As Byte 'general use variable
Dim j As Byte
Dim character(6) As Byte 'array of character font slices
Dim charbyte As Byte 'the character to send to the GLCD
Dim ilcd As Byte
Dim jlcd As Byte
Dim klcd As Byte

Dim invertchar As Bit

Config PORTC = Output
High PORTC.2
WaitMs 1000
SPIPrepare

Low PORTC.2
Gosub glcdinititalise
Gosub glcdclearscreen
High PORTC.2

glcdline = 0
Gosub glcdsetline

For i = 0 To 17
 charbyte = LookUp("HOLY CRAP IT WORKS"), i
 Gosub pickcharacter
 Gosub drawcharacter
Next i

End

glcdinititalise:
 'reset pin is pulled low via 6.2k resistor
 'wait for power to stabilise
 WaitMs 100

 'set reset pin high
 High glcd_res
 WaitMs 10

 
 glcdbyte = 0xa2 'LCD bias=1/9
 Gosub glcdsendcommand

 glcdbyte = 0xa0 'no flip on x direction
 Gosub glcdsendcommand

 glcdbyte = 0xc8 'flip on y direction
 Gosub glcdsendcommand

 glcdbyte = 0x40 'init line=0
 Gosub glcdsendcommand

 glcdbyte = 0x2c 'power control voltage convertor on
 Gosub glcdsendcommand
 WaitMs 50

 glcdbyte = 0x2e 'power control voltage regulator on
 Gosub glcdsendcommand
 WaitMs 50
 
 glcdbyte = 0x2f 'power control voltage follower on
 Gosub glcdsendcommand
 WaitMs 50
 
 glcdbyte = 0x25 'regulator resistor select
 Gosub glcdsendcommand

 'contrast control:
 glcdbyte = 0x81 'set reference voltage mode
 Gosub glcdsendcommand
 glcdbyte = 0x20 'set reference voltage resistor
 Gosub glcdsendcommand

 glcdbyte = 0xaf 'turn on the display
 Gosub glcdsendcommand

 glcdbyte = 0xb0 'set page address=0
 Gosub glcdsendcommand


 glcdbyte = 0x10 'set column address upper 4bit=0
 Gosub glcdsendcommand
 glcdbyte = 0x04 'set column address lower 4bit=4
 Gosub glcdsendcommand
 
Return

glcdsenddata:
 SPICSOn
 High glcd_a0
 SPISend glcdbyte
 WaitUs 1
 SPICSOff
Return

glcdsendcommand:
 SPICSOn
 Low glcd_a0
 SPISend glcdbyte
 WaitUs 1
 SPICSOff
Return

glcdclearscreen:
 For glcdline = 0 To 7
  Gosub glcdsetline
  glcdbyte = 0
  For j = 0 To 129
   Gosub glcdsenddata
  Next j
 Next glcdline
Return

glcdsetline:
  glcdbyte = 10110000b
  glcdbyte = glcdbyte + glcdline
  Gosub glcdsendcommand
  glcdbyte = 0x10 'set column address upper 4bit=0
  Gosub glcdsendcommand
  glcdbyte = 0x04 'set column address lower 4bit=4
  Gosub glcdsendcommand
  WaitMs 1
Return

pickcharacter:
 Select Case charbyte

  character(5) = 0 'check for this condition when drawing the letter

  Case 0, 48 '0
  character(0) = 120
  character(1) = 164
  character(2) = 148
  character(3) = 120
  character(4) = 0

  Case 1, 49 '1
  character(0) = 1
  character(1) = 136
  character(2) = 252
  character(3) = 128
  character(4) = 0

  Case 2, 50 '2
  character(0) = 200
  character(1) = 164
  character(2) = 164
  character(3) = 152
  character(4) = 0

  Case 3, 51 '3
  character(0) = 68
  character(1) = 148
  character(2) = 148
  character(3) = 108
  character(4) = 0

  Case 4, 52 '4
  character(0) = 32
  character(1) = 48
  character(2) = 40
  character(3) = 252
  character(4) = 0

  Case 5, 53 '5
  character(0) = 92
  character(1) = 148
  character(2) = 148
  character(3) = 100
  character(4) = 0

  Case 6, 54 '6
  character(0) = 120
  character(1) = 148
  character(2) = 148
  character(3) = 96
  character(4) = 0

  Case 7, 55 '7
  character(0) = 4
  character(1) = 196
  character(2) = 52
  character(3) = 12
  character(4) = 0

  Case 8, 56 '8
  character(0) = 104
  character(1) = 148
  character(2) = 148
  character(3) = 104
  character(4) = 0

  Case 9, 57 '9
  character(0) = 72
  character(1) = 148
  character(2) = 148
  character(3) = 120
  character(4) = 0

  Case 32 'space
  character(0) = 1
  character(1) = 1
  character(2) = 1
  character(3) = 1
  character(4) = 1

  Case 65 'A
  character(0) = 248
  character(1) = 36
  character(2) = 36
  character(3) = 248
  character(4) = 0

  Case 66 'B
  character(0) = 252
  character(1) = 148
  character(2) = 148
  character(3) = 104
  character(4) = 0

  Case 67 'C
  character(0) = 120
  character(1) = 132
  character(2) = 132
  character(3) = 72
  character(4) = 0

  Case 68 'D
  character(0) = 252
  character(1) = 132
  character(2) = 132
  character(3) = 120
  character(4) = 0

  Case 69 'E
  character(0) = 252
  character(1) = 148
  character(2) = 148
  character(3) = 132
  character(4) = 0

  Case 70 'F
  character(0) = 252
  character(1) = 20
  character(2) = 20
  character(3) = 4
  character(4) = 0

  Case 71 'G
  character(0) = 120
  character(1) = 132
  character(2) = 164
  character(3) = 232
  character(4) = 0

  Case 72 'H
  character(0) = 252
  character(1) = 16
  character(2) = 16
  character(3) = 252
  character(4) = 0

  Case 73 'I
  character(0) = 132
  character(1) = 252
  character(2) = 132
  character(3) = 0
  character(4) = 0

  Case 74 'J
  character(0) = 96
  character(1) = 128
  character(2) = 132
  character(3) = 124
  character(4) = 0

  Case 75 'K
  character(0) = 252
  character(1) = 16
  character(2) = 40
  character(3) = 196
  character(4) = 0

  Case 76 'L
  character(0) = 252
  character(1) = 128
  character(2) = 128
  character(3) = 128
  character(4) = 0

  Case 77 'M
  character(0) = 252
  character(1) = 8
  character(2) = 48
  character(3) = 8
  character(4) = 252

  Case 78 'N
  character(0) = 252
  character(1) = 8
  character(2) = 16
  character(3) = 252
  character(4) = 0

  Case 79 'O
  character(0) = 120
  character(1) = 132
  character(2) = 132
  character(3) = 120
  character(4) = 0

  Case 80 'P
  character(0) = 252
  character(1) = 36
  character(2) = 36
  character(3) = 24
  character(4) = 0

  Case 81 'Q
  character(0) = 120
  character(1) = 132
  character(2) = 164
  character(3) = 120
  character(4) = 128

  Case 82 'R
  character(0) = 252
  character(1) = 36
  character(2) = 36
  character(3) = 216
  character(4) = 0

  Case 83 'S
  character(0) = 72
  character(1) = 148
  character(2) = 164
  character(3) = 72
  character(4) = 0

  Case 84 'T
  character(0) = 4
  character(1) = 252
  character(2) = 4
  character(3) = 0
  character(4) = 0

  Case 85 'U
  character(0) = 124
  character(1) = 128
  character(2) = 128
  character(3) = 252
  character(4) = 0

  Case 86 'V
  character(0) = 28
  character(1) = 96
  character(2) = 128
  character(3) = 96
  character(4) = 28

  Case 87 'W
  character(0) = 252
  character(1) = 64
  character(2) = 48
  character(3) = 64
  character(4) = 252

  Case 88 'X
  character(0) = 196
  character(1) = 40
  character(2) = 16
  character(3) = 40
  character(4) = 196

  Case 89 'Y
  character(0) = 76
  character(1) = 144
  character(2) = 144
  character(3) = 124
  character(4) = 0

  Case 90 'Z
  character(0) = 196
  character(1) = 164
  character(2) = 148
  character(3) = 140
  character(4) = 0

  Case 91 'up/down
  character(0) = 0
  character(1) = 0
  character(2) = 80
  character(3) = 216
  character(4) = 80

  Case 92 'sand saver
  character(0) = 0
  character(1) = 0
  character(2) = 144
  character(3) = 168
  character(4) = 72

  Case 93 'arrow
  character(3) = 1
  character(0) = 248
  character(1) = 112
  character(2) = 32
  character(4) = 0

  Case 94 'hyphen
  character(0) = 0
  character(1) = 16
  character(2) = 16
  character(3) = 16
  character(4) = 0

  Case 58 ':
  character(0) = 1
  character(1) = 216
  character(2) = 216
  character(3) = 0
  character(4) = 0

  Case 47 '/
  character(0) = 192
  character(1) = 48
  character(2) = 12
  character(3) = 0
  character(4) = 0

  Case 62 '>
  character(0) = 124
  character(1) = 56
  character(2) = 16
  character(3) = 0
  character(4) = 0

  Case 40 '(
  character(0) = 0
  character(1) = 0
  character(2) = 120
  character(3) = 132
  character(4) = 0

  Case 41 ')
  character(0) = 132
  character(1) = 120
  character(2) = 0
  character(3) = 0
  character(4) = 0

  Case Else 'turn into a space
  character(0) = 1
  character(1) = 1
  character(2) = 1
  character(3) = 1
  character(4) = 1

 EndSelect

Return

drawcharacter:
 'at this point, we should have: charbyte containing the character index
 'which has been "passed" into pickcharacter which has populated the
 'array called "character" - 5 pixels wide, possibly more
 'so we keep sending each byte to the GLCD until we hit a sequence
 'of two empty (zero) bytes

 ilcd = 0
 jlcd = 0

 While ilcd < 5

  klcd = character(ilcd)
  If invertchar = 1 Then klcd = klcd Xor 255

  'send one byte (column of 8 pixels) to the display
  If character(ilcd) = 1 Then
   'this is the special character to say "blank"
   If invertchar = 1 Then
    glcdbyte = 255
   Else
    glcdbyte = 0
   Endif
  Else
   glcdbyte = klcd
  Endif
  Gosub glcdsenddata

  'move on to the next column of data within the character
  ilcd = ilcd + 1
 
 Wend
Return




Here's the end result:



Now if only there were some way I could keep this and use a second set of serial (SPI) lines to send/receive data to the eeprom chip. That'd be a massive leap forward....

whos.amung.us

Copyright © 2009 .Nerd Club All rights reserved. Theme by Laptop Geek. | Bloggerized by FalconHive Supported by Blogger Templates.