Hacking a LEDMatrix badge

Go To Last Post
22 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello everybody,

 

I recently started a small project in order to discover all this AVR world that is really new to me.
I have to say that I am an extreme noobie in this field, so please bare with me, I try to understand stuff, but it is sometime hard.

 

The small project is the following:
I have a led matrix badge just like this one. It works via a software. I write my text, send it and it get displayed on the led badge.

 

I would like to use in a different way, i.e. being able to send the message in command line, for that I need to hack it.

The badge has a ATMega88PA and it looks like that from the inside:

Thanks to the help of hugo, the person who wrote this post, I understood a part of what I need to do:

I first started by wiring the programmation part to flash the AVR.

So I soldered these 6 pins (MOSI, MISO, SCK, RESET, GROUND, VCC+5v) to this USBASP AVR programmer adapter.

The datasheet, can be found here. pins are page 4 (of the document, or page8 of the pdf).

 

Then I plugged it to my computer, launched avrdude, typed ""avrdude -c usbasp -p m88p" (followed these steps) and got the following errors:

 

avrdude: warning: cannot set sck period. please check for usbasp firmware update.
avrdude: error: programm enable: target doesn't answer. 1
avrdude: initialization failed, rc=-1
         Double check connections and try again, or use -F to override
         this check.

 

I have no idea what it does mean, so I looked on different websites and some say to update the firmware (no idea which one..), other say to "set the programming clock NO FASTER than 1/4 of FCPU of the target AVR.", so would this be 2Mhz here ? (the avr is 8Mhz), but I don't know how to do it, or is it something else?

Someone solved the issue by putting a "10 Pin to Standard 6 Pin Adapter Board For ATMEL AVRISP USBASP STK500".

I am waiting to receive mine to see if that helps.

Would there be any other ways to solve this so that I could flash the avr with the .hex file I have ?

 

The next step would be to wire the UART interface.

 

Thanks a lot for your help !

 

hycday

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have no idea what it does mean

Well start with:

target doesn't answer.

That seems pretty unequivocal.

 

the way avrdude/USBaspo work is that arvdude sends commands over USB to the programmer and it then uses SPI protocol to "chat" with the AVR and tell/ask it things. The first thing it does is send a kind of "hello" just to make sure they are talking (ie the wires are all connected correctly and both ends are seeing each others signals). If arvdude asks the USBAsp to send this "hello" and the AVR on the badge does not respond in anyway this gets reported back to avrdude and it says "target (the AVR) doesn't answer".

 

So there's something wrong with the wiring or perhaps the AVR has been "knobbled" in some way to ensure it deliberately does not answer.

 

The picture of the badge is too small to see what AVR it is but, for example, many low pin count AVRs have a mechanism called RSTDISBL (Reset Disable) that can be set as a last minute thing during programming that turns the reset pin into a useable IO pin. However once reset is disabled SPI/ISP can no longer be used. So, although the silk screen of this circuit labels MOSI/MISO/SCK/RESET it could be (because RESET no longer exists) that these were only used during production and those signals are now effectively "dead".

 

On the other and the reason ISP is not working may actually be something similar like you got MOSI and MISO the wrong way round (try switching them) or that some of the other signals (like SCK) have been mis-identified and the pinout on that header is actually some other order.

 

If you have a logic analyser or an oscilloscope it can make identifying this kind of thing MUCH easier.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

thanks a lot for your answer!

so the message I get from avrdude should be seen as 3 different messages (1- cannot set sck period 2- target doesn't answer 3- initialization failed, rc=-1), or one that had multiple consequences?

I ask this because I would like to understand why did you focus on the second one and not the first one (cannot set sck period) ? Maybe by setting the sck period, the target would answer ? or it does not work like this ?

 

The AVR is an "Atmel AVR ATMega88PA" but I did not touch that part yet, I only worked on the programming part (blue rectangle, number 4, on first picture). I will then wire the AVR to the UART programmer following those 4 pins (TX/RX/GND/VCC):

but that's the next step.

From what hugo wrote in his post, there should not be a RSTDISBL mechanism or else, as he managed to to this.

 

As the pins are really small, and as I am not an excellent solder, do you think that the issue might come from my soldering skills and that I could give it a second try, maybe I did it wrong and therefore the connection is not good.

I will also try switching MOSI and MISO hoping to not 'break'/'burn' anything.

 

Is there any chance that the "10 to 6 pin adapter" would solve anything (if it doesnt come from my soldering skills, nor the RSTDISBL mechanism) ?

 

 

Last Edited: Tue. Aug 18, 2015 - 01:19 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

From what hugo wrote in his post

The link didn't work for me so I have no idea what has been found previously.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yeah I know, his server goes up and down quite frequently....

It is in french so here is the google translator link: https://translate.google.com/tra...

 

Otherwise, here is the content translated (that I will remove after to let him the credits on this website)

Introduction

DealExtreme offers for € 7.9, a display LED (red, blue) powered by a button cell and programmable by the buttons on the back of the latter, in addition to all this, it is vaguely indicated that there USB connection for programming can be from a PC.

It has 203 LEDs arranged in 29 columns of 7 LEDs.

A few weeks after ordering, I get this display, it works perfectly well, unfortunately, the USB connector is of an unknown type, then disassembly needed to learn more about it, no screws, you will have to use a rather brutal way to separate the two shells glued.

Once opened, more surprises, good and bad:

  • The USB connector is not likely to work, it is connected anywhere (I shall see how me later why)

  • Everything is controlled by a single micro-controller, an Atmel AVR ATmega88, no multiplexer ...

  • A programming port is available

A question then arises, how he gets to fly as many LED with a single micro-controller with a total of 3 ports of 8 bits? knowing that it theoretically has a USB port to manage and programming buttons 7 and an external EEPROM?

Opening the box

The housing consists of 2 parts heat-bonded to each other, yes, put the screws would have been too expensive and then <irony> anyway, who wants to remove the </ irony>

So, the opening is not really a pleasure and it will take you to a cutter following the joining of the two hulls to loosen them.

How it works ?

Overview

Our main area of ​​the module:

  1. USB connector owner

  2. The heart of the installation, the AVR

  3. The switch

  4. The connector for the programming

  5. An EEPROM to store messages

In the center, we see the location of the button battery on the left, 6 buttons and finally 1 single button at the top right.

The heart

The heart of the installation is an Atmel AVR ATMega88PA in a TQFP housing and these are the main features:

  • 8 KB of Flash memory (ready shoes foot)

  • 512 KB EEPROM

  • Two 8-bit timers

  • 1 16-bit timer

  • 23 inputs / outputs

  • Supply voltage range 1.8V to 5.5V (3V button battery)

  • Very low power consumption (hence the possible use with a decent battery life with just one button battery)

It is clocked at 8Mhz through the internal oscillator thus avoiding having to add an external crystal and saw that the accuracy of the time base is not sought in this circuit is quite suitable .

Programming interface

A connector is available and allows you to program as we see fit the AVR. Originally, it is obviously unreadable, protected access to the manufacturer code in the AVR through the appropriate fuses.

The programming connector, we do not really know where he comes from, it is not compatible with standard connectors ISP6 but easily adaptable:

If you accidentally make a mistake with the fuses and that the AVR does not respond, it is always possible to reprogram it in parallel but this is not recommended;):

The USB interface

The USB connector is proprietary and therefore can not connect any USB cable above.

Originally, the USB interface has absolutely no chance of working:

  1. USB data lines D + and D- are shorted

  2. Missing components (Q2, R12 and R13) which appear involved in a possible management of the port (no one knows how the magic can be)

  3. The AVR is clocked at 8Mhz internally, it is highly unlikely, even in "Low Speed" mode it is possible to manage anything protocol (Project V-USB indicates that a minimum frequency of 12Mhz)

In fact, the USB interface Dealextreme described on the site look more like an RS232 serial interface because if we follow the tracks of the RX and TX pins on the AVR, you come straight over Q1, R9, R12, R13, Q2 which they give to the external connectors.

Buttons management

The 7 buttons are simply connected to one input of the AVR, and not just any, to an input connected to the ADC (Analog to Digital Converter), each form button, when pressed, through well placed and resistors correctly dimensioned, a voltage divider bridge.

The advantage of this way of doing this is that you can handle multiple buttons with only one pin of micro-controller used, the major drawback of this method is that the management several buttons pressed simultaneously is found somewhat complicated ...

Here is the principle:

When a button is pressed, current flows through the latter and the resistor connected to ground (R1, R2 or R3) then forming a divider bridge with the resistance Rup connected to the supply voltage. Is then from the ADC input, a tenstion to know which button has been pressed.

Here is how I named buttons, seen from behind:

The correspondences between the buttons and the values ​​returned by the CAN

Button Value
TO 128
B 155
C 79
D 57
E 19
F 42
G 192

Buttons made of metal, when pressed, the value returned by the ADC fluctuates, so if you press the A button, you get 128, 129, 127, etc ... software processing is done to smooth all that expanding the fields permissible value for a button (eg for A, that is from 126 to 130, etc ...)

LED matrix

203 LEDs, arranged in seven rows by 29 columns are used in this assembly, yet only 15 data lines used to control the screen, and no other integrated circuit is not there, by what clever way do they do?

Ports B, C and D are used for controlling LEDs, the port B is used around while bits 0-3 are used to port C and the bits 5-7 are used for port D recap:

Use of ports for powering the LEDs

Port B

7 6 5 4 3 2 1 0

Port C

x x x x 3 2 1 0

Port D

7 6 5 x x x x x

With 15 lines, it would not be possible to drive with 203 LEDs arranged as in a conventional matrix, we arrive at best, with a square layout to 56 LEDs.

The solution they found was to use line capacity of the ports of the AVR to put themselves in a state said high impedance means that as well as the Three-State Logic is a state in which the current does not flow at all, it's like this, we had an open switch, it allows total isolation.

tristate_buffer

(Wikipedia Image)

On the above image, it is understood well enough the operation of the 3-state logic gate, until the command B is inactive, the door normally works with only two states, and, in the case of a standard buffer ( YES door), applying a high state at the input A, the output C, we will also have a high state, if one activates the high impedance function through the B input, the door will switch to high impedance, the current can no longer be driven on the output of the gate.

In the circuit, each bit ports controlling the LEDs 14 LEDs can be switched on simultaneously, but depending on the configuration of the other ports (low, high or high impedance level), 1 one or more LEDs will light.

To know which combination of value should be sent to the ports to make such LED light, it took virtually reconstruct the mapping connections to ports and LEDs test different combinations possible. A magnifying glass I was also a good help to see the physical connections on the display.

We see with the naked eye connections reliants LEDs them (difficult to see from the picture).

Update: Apparently, we are dealing with a type of multiplexing Charlieplexing

Source code

To display a single pixel is needed to feed six memory areas: the 3 ports B, C and D (PORTB, PORTC and PORTD) and the ports of directions (DDRB, and DDRD DDRC), all these values ​​are stored in the program memory in a multidimensional array for each column, values ​​6 x 7, 7 being the number of lines.

Here is an excerpt of the table:

  unsigned char matrix [29] [7] [6] = {PROGMEM

  // 0
 {
     {4, 4, 0, 4, 0, 0},
     {2, 4, 0, 2, 0, 0},
     {1, 4, 0, 1, 0, 0},
     {0, 4, 128, 0, 0, 128},
     {0, 4, 32, 0, 0, 32},
     {128, 4, 0, 128, 0, 0},
     {64, 4, 0, 64, 0, 0},
 },

 // 1
 {
     {4, 0, 64, 0, 0, 64},
     {2, 0, 64, 0, 0, 64},
     {1, 0, 64, 0, 0, 64},
     {0, 0, 64 + 128, 0, 0, 64},
     {0, 0, 64 + 32, 0, 0, 64},
     {128, 0, 64, 0, 0, 64},
     {64, 0, 64, 0, 0, 64}
 },

 [...] 

So when you want to light a pixel, it uses the function setled who will look to pick up the data and put it where you need to turn on the right LED.

  inline void setled (unsigned int x, unsigned int y) {

     if (x> = MATRIX_COL_COUNT || y> = MATRIX_LINE_COUNT) {
         return;
     }

     // Reset all ports
     DDRB = DDRC DDRD = = 0;
     = PORTC PORTD = PORTB = 0;

     DDRB pgm_read_byte = (& (matrix [x] [y] [_DDRB]));
     DDRC pgm_read_byte = (& (matrix [x] [y] [_DDRC]));
     DDRD = 0b11100000 pgm_read_byte & (& (matrix [x] [y] [_DDRD]));

     Pgm_read_byte PORTB = (& (matrix [x] [y] [_PORTB]));
     Pgm_read_byte PORTC = (& (matrix [x] [y] [_PORTC]));
     PORTD = 0b11100000 pgm_read_byte & (& (matrix [x] [y] [_PORTD]));
 } 

Access to external EEPROM

Todo

I did not investigate on that because not completely essential ...

Add a series connection

Here is where it is possible to connect the card to access the UART interface of the AVR, in red, the TX, RX green (compared to April).

Once the installation of the adapter for programming (connector in the middle above) and the connector for the UART interface (4-pin connector slightly left to bottom):

The UART I placed connector has 4-pin to carry TX, RX, GND and VCC to power directly from the connector assembly.

You want to run the installation directly from a USB module

Well practices USB modules to interact with the modules through a serial link, they do not cost much chèr and drivers are available for all OS:

Personally, I use a model from 4DSystems ordered from Sparkfun for development, it has the advantage of operating both with voltages of 3 or 5V (for the serial line): Breakout Board for USB to Serial FT232RQ

Modules are also available in France at Lextronic:

If you already have a RS232 serial connection

A RS232 serial connection works using oscillating signals between + 12V and -12V, for plugging this mounting worry over a RS232 connection, you need an adapter levels that will convert the voltage levels into something understandable by the 2 parties.

The schematic diagram below works with the famous MAX232 which is a level converter serial / TTL, the pattern is easily reproducible on a perforated card:

The free firmware

The source code for the AVR firmware (firmware) is available on GitHub at: https://github.com/hugokernel/203LedMatrix, it has been developed with the free compiler toolchain AVR-GCC and the AVR Studio development environment.

Source files:

  • font5x7.h This file contains the definition of ASCII characters displayable by the display

  • LedMatrix.c This is the file containing the main code

  • LedMatrix.h The header file containing the different possible configurations

  • usart.h The source code used to control the serial link

There are 2 modes to control the display mode is to drive the display directly from a terminal, very convenient to test live, this mode is the interactive mode, and another mode made specifically to be controlled from a script This mode has no menu and is reliable enough to be used on a 24/7 server.

The choice of mode is done at compile time by editing the constant INTERACTIVE_MODE LedMatrix.h the file.

Interactive mode

Interactive mode allows you to control the screen directly from a serial link into a console with menus.

Here catch a console view after the connection established with the screen:

  M: [1], S [9], D [1] L: [0] C: [1]
 Action:
  [0 ... 3] Select msg
  [t] Edit msg
  [c] Clear
  [s] Set scroll speed ...
  [t] Letter spacing ...
  [d] Reverse the direction
  [a] Chain mode
  [w] conf Save to EEPROM
  [b] Read button ...

 Your choice: 

Above, we distinguish the status line "M: [1], S [9], D [1] L: [0] C: [1]" to see:

  • M: [x] Message number

  • S: [x] Playback speed

  • D: [x] Scroll Direction

  • L: [x] space between letters

  • C: [x] chaining message or not

In interactive mode, it is possible to record 4 messages (0-3) in the EEPROM, the message is selected by directly entering its number in the terminal, it is loaded.

Then you see the actions with identifiable names, so I will not go into more details except for the action "Chain mode", it displays in turn posts.

Non-interactive mode

This mode allows an automated script to send commands to the display, the interactive mode seen above is not suitable for this, this batch mode is much more reliable, for against, his approach is much less intuitive, normal since been designed to interact with a piece of code and not with a human ...;)

explanation of the protocol

Here is the list of commands available in this mode:

  • m (Message): Edit Post

  • s (Speed): Change the speed of the scroll

  • d (Branch): Change scroll direction

  • l (letter Spacing): Spacing between letters

  • e (EEPROM): Save the message in the EEPROM

  • p (Print): Display message on the serial link

  • c (Conf) Showing conf on the serial link

  • w (Watchdog): Dog Guard Configuration

  • v (Verbose): Set the verbosity level

Orders expectant arguments (m, s, d, l, w, v), some not (e, p, c).

It is considered as the host device sending commands to the display module and the target being the display.

Sends a command with no arguments

  1. Sends the character associated with the (e, p, c)

  2. In response, the same character is returned

  3. The command is executed directly asked

Sends a command with argument

  1. Sends the character associated with the command (s, d, l, w, v)

  2. In response, the same character is returned

  3. Sends the argument (ascii value between 0 and 9 included included)

  4. Validation of the argument by sending a carriage return (CR, Carriage Return, code 013, input from a terminal key)

  5. The value is returned as an acknowledgment

Sends a command m (Message)

  1. Sends the character m

  2. The target will sent an acknowledgment (catactère a point ".") Indicating that it is ready to receive the message (end of the scroll)

  3. Once the character received, you can send the message

  4. Confirm the end of the message by sending a carriage return (CR, Carriage Return, code 013, input from a terminal key)

  5. As an acknowledgment, three characters you are then returned, they represent the number of characters that included the message (eg message 009 for nine character)

Note 1: To send the message, in step 2, until the acknowledgment character is not received, we must wait to move on.
Note 2: When sending messages, it is important to observe a minimum interval between each character otherwise characters will be ignored.

 

Last Edited: Tue. Aug 18, 2015 - 01:31 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

oh wow...I just tried it from scratch. removed all the wiring, soldered the thing back, with a magnifying glass, and as simply as that, it was recognised by avrdude.

I sent the "avrdude -c usbtiny -p m88p -U flash:w:LedMatrix.hex" command and saw the thing getting written on the AVR !

 

So now, last part, I need to solder the last 4 wires: TX/RX/GND/VCC.

According to this picture :

The red pin on the AVR would be the TX, the green pin on the AVR would be RX.

But what are the red and green circles ? Is the red circle the VCC and the green circle the GND ?

Once I finish this, I'm all done I think !

 

Last Edited: Tue. Aug 18, 2015 - 06:17 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

No, I don't think you are interpreting that correctly.

 

I think the Green circle and the Green uC pin are likely the same signal, the USART RxData; and the Red circle and the Red uC pin are the same signal, the TxData.

You can tap off either of the locations to obtain the signal.

That's my guess, I don't have one in front of me.

 

You would get the Vcc and Ground from the 6-Pin programming header along the top of the board.

You probably already have a wire soldered to those signals for the programmer.

 

Nicely documented reverse hack, above, BTW!

 

JC

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

oh I see ! 

So to ease it up, I could actually wire TX and RX to the red and green circle (easier than the two tiny pins on the AVR), and use the VCC and GND that I used previously.

I connect all of these to the UART programmer...

and then - and sorry to ask a silly question, but I really think I am soooo close to it - what to do... I mean, how to speak with the Led Matrix to send my commands ? should I run a software on my computer or do I need a particular connection and send something in command line or what to do ? I never used such things..

thanks for all your help ! 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

There are 2 modes to control the display mode is to drive the display directly from a terminal, very convenient to test live, this mode is the interactive mode, and another mode made specifically to be controlled from a script

 

 

First, I think, you have to load the software into the AVR.

Then, as mentioned above, that new software has two methods to control it.

 

The easiest method is to connect the USART to a PC and run a Terminal Program, (HyperTerminal, TeraTerm, etc.)

BUT, PC's serial ports use RS-232, (typically +/- 12 V), NOT 3 V or 5 V logic level signals.

So, one has to use an RS-232 converter, e.g. Max232 chip, or breakout board from Spark Fun, Ada Fruit, etc.

OR

Use a logic level to USB converter, which is what is shown in the hack above using a FTDI chip.

Pre-made breakout boards, and pre-made cables are also available.

 

Either one converts the micro's logic level serial to either RS-232 or USB, which the Terminal Program can then communicate through.

 

BUT, don't forget, you need to get the new software into the micro for the above to work.

 

JC 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

DocJC wrote:

First, I think, you have to load the software into the AVR.

...

BUT, don't forget, you need to get the new software into the micro for the above to work.

 

yes, isn't that what I did via the programmer and my avrdude command ? I flashed the AVR with this software: https://github.com/hugokernel/20...

 

 

DocJC wrote:

BUT, PC's serial ports use RS-232, (typically +/- 12 V), NOT 3 V or 5 V logic level signals.

So, one has to use an RS-232 converter, e.g. Max232 chip, or breakout board from Spark Fun, Ada Fruit, etc.

OR

Use a logic level to USB converter, which is what is shown in the hack above using a FTDI chip.

 

I bought this product for the UART part http://www.ebay.fr/itm/Modulo-Ad...?

I don't speak spanish but the translation I got was about right. And it looks like the logic level to usb converter that is in hugo's post.

 

DocJC wrote:

The easiest method is to connect the USART to a PC and run a Terminal Program, (HyperTerminal, TeraTerm, etc.)

So that would be my final step now, I wire the 4 UART pins to my adaptor (link above), then send command via a Terminal Program !

Will try this tomorrow and keep you posted.

 

Again, THANK YOU ! your help is precious.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Good Luck!

 

JC

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

...even on this last part I tend to find some difficulties !

so I soldered the TX and RX wires.

I took my usb-to-serial UART key (FT232RL), installed the driver, made the link with the 4 wires RX/TX/GND/VCC, plugged it in, and checked that it is correctly detected...

success it in on COM2, even the Arduino IDE sees it.

 

I launched TeraTerm, selected the COM2 and........nothing, nothing displayed at all.

Same with Real Term, Termite etc. 

And I cannot type anything neither.

 

As I don't have any error, and the thing is detected, I don't know where to look at to solve this. Any ideas ?

 

Thanks again for your help

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Does the uC have a divide clock by 8 use?

Is it set, or cleared, and which way does the code expect it to be?

 

If you have any experience writing code for this uC, then I'd write a program to flash of of the many LEDs on and off, at a given rate, such as 1 Hz.

Then see if you can down load that and watch the LED flash.

 

That proves that you can actually download a program to the uC, and that the uC is running at roughly the correct speed.

 

Then try downloading the real program again.

 

Also, with your programmer, make sure you can read the micro's Signature, and that the read back is correct.

 

JC

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

DocJC wrote:

Does the uC have a divide clock by 8 use?

Is it set, or cleared, and which way does the code expect it to be?

The AVR frequency is 8Mhz. I don't know what do you mean by 'divide clock by 8 use'? Are you referring to the fact that "the programming clock should be NO FASTER than 1/4 of FCPU of the target AVR" ? Therefore set at 2Mhz ? If so, how to do that ? 

I know that the code was written by the same person who did the article so it should be working as is.

 

DocJC wrote:

If you have any experience writing code for this uC, then I'd write a program to flash of of the many LEDs on and off, at a given rate, such as 1 Hz.

Then see if you can down load that and watch the LED flash.

Not really..not at all in fact :(

The full code is here https://github.com/hugokernel/20... and I can try to have a look, but it will be hard for me to learn how to code that now...however I see the utility. 

You are suggesting to use a simplier code, just to test if everything is working. right ?

 

DocJC wrote:

Also, with your programmer, make sure you can read the micro's Signature, and that the read back is correct.

When I send my command to avrdude, it displays "cannot set sck period' but then it reads 100%, reads the input file, writs it 100%, verifies flash memory against the .hex file, reads again 100%, and finishes by "Fuses OK", and "Thank you" (basically).

I assumed all went well, but now I am wondering about the "cannot set sck period" message...is this something I should worry about or that could be the source of the issue ?

 

Thank you DocJC

 

 

Last Edited: Wed. Aug 19, 2015 - 10:07 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I don't use AVRDude, so I can't comment on its messages, and when it is working successfully or not.

 

Does the uC have a divide clock by 8 use?

Sorry about that, typo on my part.

 

All of the AVR's have "Fuses", which are essentially internal registers that can be set by an external programmer.

 

All of the AVR's have a "Signature", three hex bytes that define the specific chip. 

One can use a programmer to read the Signature of the micro the programmer is connected to.

The Signature is in the data sheet, and elsewhere.

 

It is always wise, when first connecting an external programmer to program a hex file into a micro to read the micro's Signature first, and make sure you are reading back the Signature of the micro you are programming.

If you connect the programmer to a MegaXYZ micro, then you ought to read back the Signature of the MegaXYZ micro, not some other garbage hex bytes.

Correctly reading the Signature lets you know that the micro has a clock signal, the micro is "running", and the connection between the programmer and the micro is working.

 

If you can't read the Signature correctly, there is no need to try programming a file into the micro, as there is an underlying problem present.

 

Next, many of the AVR's have a Divide By Eight FUSE.

This Fuse internally divides the clock by 8 before driving the remainder of the micro. 

So, a micro running on an internal 8 MHz RC Osc, with the Fuse enabled, is actually running at 1 MHz.

A micro running on a 16 MHz external crystal, with the Fuse enabled, would actually be running at 2 MHz.

This matters, in your case, because the USART communications is based upon the Baud Rate, and the baud rate could be off by a factor of 8, depending upon how the original programmer had the micro's Fuses set, and how you have them set.

 

Blinking an LED is a simple way to tell if your clock is off by a factor of 8 or not, from what you think it is running at.

It also confirms that the micro is running, and that you were successful in downloading a program to the micro.

 

JC

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi,

 

I am bumping this thread as I didn't totally solve my issue.
I worked on it for a while, then put it on standby and am now trying to solve it again. My main concern now is on the software/code part.

 

As a quick update I managed to make the LED screen work: compile the code, and flashing the AVR with the hex file.
The code is based on the 4 main files here : https://github.com/hugokernel/203LedMatrix

 

The usart.h, the font5x7.h, the LedMatrix.h and the LedMatrix.c

 

I modified the LedMatrix.c (see below) to simplify it to my needs.

 

So now :
I open a terminal, send "m" then ENTER. Once I get a response "." in terminal. I can start entering a text (example "test"), then "ENTER" to show end of text.
The text is displayed AS SOON as I type it, letter by letter, so I must not write too fast.
I receive the size of text (example for "text" : "004") in terminal.

 

What I want to do is :
I open a terminal, send my text (example "hello world"), then ENTER, and THEN the text is displayed on the LCD screen and I get size of text in terminal (example : "011" here).
I don't want to use the "m", the "." and don't want instant display, I prefer to send all my text at once and display it at once.
Then if I enter "test number 2" in the terminal, then ENTER, I want this new text to be displayed instead of "hello world". Not append it at the end of "hello world".

 

I have no idea how to manage that new part and what to change in the code.

I would really appreciate any kind of help.

 

The code doesn't seem to be very long to work on, but I am not very familiar with the language...

 

Code for new version of LedMatrix.c :

 

#include "LedMatrix.h"

inline void setLed(unsigned int x, unsigned int y) {

    if (x >= MATRIX_COL_COUNT || y >= MATRIX_LINE_COUNT) {
        return;
    }

    // Reset all ports
    DDRB = DDRC = DDRD = 0;
    PORTB = PORTC = PORTD = 0;

    DDRB = pgm_read_byte(&(matrix[x][y][_DDRB]));
    DDRC = pgm_read_byte(&(matrix[x][y][_DDRC]));

    DDRD = 0b11100000 & pgm_read_byte(&(matrix[x][y][_DDRD]));

    PORTB = pgm_read_byte(&(matrix[x][y][_PORTB]));
    PORTC = pgm_read_byte(&(matrix[x][y][_PORTC]));

    PORTD = 0b11100000 & pgm_read_byte(&(matrix[x][y][_PORTD]));
}

inline void clearLeds() {
    // Reset all ports
    DDRB = DDRC = DDRD = 0;
    PORTB = PORTC = PORTD = 0;
}


inline void writeLine(char * str, int offset) {
    char col, tmp = 0;
    int x = 0;
    unsigned int start_2 = 0;
    int start = 0;
    char ii = 0;
    char i = 0;
    unsigned char b = 0;

    unsigned int offset_abs = abs(offset);

    if (offset < 0) {
        start_2 = offset_abs % 5;
        x = 0;
        start = offset_abs / 5;
    } else {
        start_2 = 0;
        x = offset;
        start = 0;
    }

   

    for (col = start; x < MATRIX_COL_COUNT; col++) {

        tmp = (col < message_size) ? str[col] : ' ';

        for (i = start_2, ii = 0; i < 5; i++, ii++) {    
            for (b = 0; b < 7; b++) {
                if (pgm_read_byte(Font5x7 + (tmp - 0x20) * 5 + i) & (1 << b)) {
                    setLed(x + ii, b);
                    asm("nop");
                    asm("nop");
                } else {
                    clearLeds();
                }
            }

            start_2 = 0;
        }
        
        // Ecart entre les lettres
        x = x + ii + char_spacing;
    }

    clearLeds();
}


#define SEND_ACK  printf("."); 

#define RESPONSE(c) USART_SendByte(c);


inline char waitData() {
    char value = 0;
    while (!receivedBuffer);
    value = receivedBuffer;
    receivedBuffer = 0;
    return value;
}

void handleAction() {

    char command = 0;
    char data = 0;
    int size = 0;

    char key, key_tmp = 0;
    char value, in = 0;

    SEND_ACK

    receivedBuffer = 0;
    while (1) {

        command = 0;
   
        // Wait for command
        while (1) {

            if (receivedBuffer) {
                command = receivedBuffer;
                receivedBuffer = 0;
                break;
            }

            ADCSRA |= (1 << ADSC) | (1 << ADIE);
            value = adc_value;        
            if (value > 126 && value < 130) {           // 128
                key = 'A';
            } else if (value > 152 && value < 157) {    // 155
                key = 'B';
            } else if (value > 76 && value < 82) {      // 79
                key = 'C';
            } else if (value > 54 && value < 59) {      // 57
                key = 'D';
            } else if (value > 17 && value < 23) {      // 19
                key = 'E';
            } else if (value > 40 && value < 47) {      // 42
                key = 'F';
            } else if (value > 189 && value < 195) {    // 192
                key = 'G';
            } else {
                key = '?';
                continue;
            }

            // Todo: Faire une boucle d'attente de message sur le port serie...??
            _delay_ms(100);

            if (key != key_tmp) {
                printf("%c", key);
                key_tmp = key;
            }

            ADCSRA |= (1 << ADSC) | (1 << ADIE);
            if (adc_value > 250) {
                printf("%c", tolower(key_tmp));
                key_tmp = 0;
            }
        }

        if (isspace(command)) {
            continue;
        }

        // Response
        _delay_ms(500);
        RESPONSE(command);

        switch (command) {
            case 'm':
                data = 0;

                const char tab[] = { 5, 5, 4, 4, 3, 3, 3, 3, 2, 2 };

                // Wait for first char
                size = message_size * (5 + char_spacing);
                while (1) {
                    if ((index - STEP) == -size) {
                        _delay_ms(100);
                        SEND_ACK
                    }

                    if (receivedBuffer) {
                        data = receivedBuffer;
                        receivedBuffer = 0;
                        break;
                    }
                }
          
                message_size = 0;
                memset(message, 0, sizeof(message));
                while (1) {
                    // Return ?
                    if (data == 8) {
                        message[--message_size] = 0;
                        continue;
                    }

                    // Enter pressed ?
                    if (data == 13) {
                        break;
                    }

                    message[message_size++] = data;

                    // Test max string size
                    if (message_size == sizeof(message) - 1) {
                        break;
                    }

                    data = waitData();
                }

                _delay_ms(500);

                // Send message size
                printf("%03i", message_size);
                goto end;
            default:
                continue;
        }


end:
printf("\n\r");
    }
}



ISR(TIMER0_OVF_vect)
{
    writeLine(message, index);
}

ISR(TIMER1_OVF_vect)
{
    int size = message_size;

        size *= (5 + char_spacing);
        if (scroll_direction) {
            index = index - STEP;
            if (index < -size) {
                index = MATRIX_COL_COUNT;

            }
        } else {
            index = index + STEP;
            if (index > MATRIX_COL_COUNT) {
                index = 0 - size;

            }
        }

    TCNT1H = speed_table[scroll_speed];
    TCNT1L = 0;
}

ISR(TIMER2_OVF_vect)
{
    if (watchdog_value && watchdog_counter++ >= watchdog_table[watchdog_value]) {
        SET_MESSAGE(WATCHDOG_ERROR_MSG)
        WATCHDOG_RESET
    }
}

ISR(ADC_vect)
{
    adc_value = ADCH;
}


void loadData() {
    int i = 0;


    eeprom_read_block((void*)&message, (const void*)EEPROM_CONFIG_ADDR_MESSAGE, sizeof(message));

    // First boot ?
    char found = 0;
    for (i = 0; i < sizeof(message); i++) {
        // No 0 ?
        if (!message[i]) {
            found = 1;
            break;
        }
    }

    if (!found) {
        memset(message, 0, sizeof(message));
    }

    message_size = strlen(message);

    scroll_speed = eeprom_read_byte((const void*)EEPROM_CONFIG_ADDR_SPEED);
    if (scroll_speed != 8) {
        scroll_speed = 8;
        eeprom_update_byte((const void*)EEPROM_CONFIG_ADDR_SPEED, scroll_speed);
    }

    scroll_direction = eeprom_read_byte((const void*)EEPROM_CONFIG_ADDR_DIRECTION);
    if (scroll_direction != 1) {
        scroll_direction = 1;
        eeprom_update_byte((const void*)EEPROM_CONFIG_ADDR_DIRECTION, scroll_direction);
    }

    char_spacing = eeprom_read_byte((const void*)EEPROM_CONFIG_ADDR_SPACING);
    if (char_spacing != 1) {
        char_spacing = 1;
        eeprom_update_byte((const void*)EEPROM_CONFIG_ADDR_SPACING, char_spacing);
    }

    intensity = eeprom_read_byte((const void*)EEPROM_CONFIG_ADDR_INTENSITY);
    if (intensity >= 9) {
        intensity = 9;
        eeprom_update_byte((const void*)EEPROM_CONFIG_ADDR_INTENSITY, intensity);

/*
// see if keep ?
                if (intensity) {
                    TCCR0B = (0<<CS02) | (1<<CS01) | (1<<CS00);
                } else {
                    TCCR0B = (1<<CS02);
                }
*/

    }

    watchdog_value = eeprom_read_byte((const void*)EEPROM_CONFIG_ADDR_WATCHDOG);
    if (watchdog_value >= 9) {
        watchdog_value = 9;

/*
// see if keep ?
                if (watchdog_value) {
                    WATCHDOG_RESET
                    TIMSK2 |= (1<<TOIE2);
                } else {
                    TIMSK2 = 0;
                }
*/

        eeprom_update_byte((const void*)EEPROM_CONFIG_ADDR_WATCHDOG, watchdog_value);
    }


}

int main(void) {

	clearLeds();

    // Timer 0 configuration : Print message
    TIMSK0 |= (1<<TOIE0);
    TCCR0A = 0;
    TCCR0B |= ((0<<CS02) | (1<<CS01) | (1<<CS00));
    TCNT0 = 0;

    // Timer 1 configuration : Scroll message
    TIMSK1 |= (1<<TOIE1);
    TCCR1A = 0;
    TCCR1B |= ((0<<CS12) | (1<<CS11) | (1<<CS10));
    TCCR1C  = 0;
    TCNT1 = 0;

    // Timer 2 configuration
    TIMSK2 |= 0;
    TCCR2A = 0;
    TCCR2B |= ((1<<CS22) | (1<<CS21) | (1<<CS20));
    TCNT2 = 0;

    // Init ADC
    ADMUX = 0b01100110;

    //set prescaller and enable ADC
    ADCSRA |= (1 << ADEN) | (1 << ADIE);

    USART_Init();
    stdout = &mystdout;

    memset(message, 0, sizeof(message));

    loadData();

    sei();

    DDRD = 0;
    PORTD = 0;

    handleAction();
}


 

 

 

Thank you in advance for your time !!

Last Edited: Tue. Aug 9, 2016 - 06:20 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This seems to be a LOT of work when an Arduino Uno and an LED matrix shield would have been a much easier route.  (good job on the hack!)

 

If you don't know how to code in C, then its time to hit the utube video's and start learning to code.  Pick up a copy of the K&R book, "The C programming Language" its a must have for any c programmer.  Welcome to a wider world!

 

 

Jim

 

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274
get $5 free gold/silver https://www.onegold.com/join/713...

 

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for your answer Jim.

Yes it would have been easier, but then less fun. I used this project to try to learn playing with AVR. I had this led screen around ready to go to garbage, and I had a USBASP, so I just wanted to try it.

 

I'm almost done as it is now working as I said, the only thing missing is some modifications in the code to best suit the use I want. 

 

I found a software to communicate in serial in command line, but the way the AVR code is now makes it buggy because of the "m" and "." stuff described in my previous post.

 

I am trying to have a look at it and as you can see, I have been on this project for a year.

This is totally out of my skills and work industry but I am eager to learn and trying hard.

However, for the changes I want in the code, I am not sure how learning a language from scratch would be pertinent. It is as if you go to a car garage and the team tells you to get an engineering degree in mechanics :( 

You know just like me that to understand the details of this code I need more than just learn C from youtube and a book.

 

In the code, I tried to change the handleAction function, but it seems the AVR interpret all letters one by one, whereas I want it to keep them in buffer until it receives an "ENTER" (with a limit for memory purpose, that when reached would automatically send the text to screen even if ENTER is not pressed).

 

My changes were of no success. I think the rest of the code doesnt need changes but not sure as I don't get it all (especially all the parts that look like the end with the Timer 0/1/2 etc).

 

Again, I am not coming like a flower, asking for a total code as if I havent been working on the thing on my side. 

 

Thank you for any kind of help.

 

day

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Can u post hex file

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You mean like the one that is on this page? :

 

https://github.com/hugokernel/203LedMatrix/tree/master/default

 

He (indirectly) gave the link to this in post #16

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

more wondering what he is up to at all. First he wants us to make a hex file for a ssd1306 display and now he askes also here for a hex file.

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

meslomp wrote:
First he wants us to make a hex file for a ssd1306 display

Here: https://www.avrfreaks.net/commen...

 

and now he asks also here for a hex file.

 

And both in old threads!

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...