QUUBmon - yet another monitor program

There's been some activity around monitor programs lately with a good version by Vanyamba being the most recent. So why another one?

Well AFAIK my monitor is the only one that uses a second Arduino to do all the hard work, so there is very little affect on the Arduino being debugged.

The monitor is divided into two parts, a server and a client.

Server
QUUBmon has a very small server running on the target system, it's about 500 bytes in size and uses no system RAM except about 35 bytes of stack space. Each access to the server is atomic, meaning that all business is done within the ISR. As this normally takes about 100uS I think that's a reasonably small hit on the target program.

The server talks to the other Arduino (the client) via bit banged SPI so it needs three spare pins, but they can be any pins.

The server sits on the watchdog interrupt, an interrupt that is almost never used by Arduinoites as far as I can tell. It could easily be moved to another interrupt though, say a timer and maybe a polled version could be made.

There are two versions of the server software, assembly language and C, but I think C will be the only one supported in future.

Client
The client handles a simple command-line UI via USB to a PC, so all that is needed is a dumb terminal program.
The client is currently able to run on either a 2560- or 328-based Arduino.

Target processors
The software is table-driven so it's easy to add a processor. So far the following are supported (by "support" I mean that the program knows what registers and peripheral devices the processor has and their addresses).

• ATmega2560*
• ATmega328
• ATtiny861
• ATtiny85
• ATtiny84

  • When debugging a 2560 or derivative on a 328-based client full mnemonic descriptions of the register bits are not available due to lack of program space to store the strings.

Commands
RD - Read a single byte from the target RAM.
WR - Write a byte to target RAM.
L - Do a HEX dump of 16 bytes (a “line”) from the target RAM.
P - Do a HEX dump of 128 bytes (a “page”) from the target RAM.
REGS - Display the target processors registers (only with an assembly language server)
IO - Display the target processor’s IO registers.
F - Fill target RAM with a value.
SP - Display the target processors stack pointer and the values on the stack.
PER - Display detail about the target processor’s “peripherals”.
WATCH - Periodically sample a memory or IO location on the target processor.
RST - Reset the target processor.
IPC - Find or dump the IPC (Inter Processor Comms) area of RAM on the target system.
SET - Set a variable in the IPC.
DIG - Display all Arduino digital pins on the target system.
AN - Display all Arduino analogue pins the target system.
PIN - Display and control Arduino digital pins.
PC - Display the target processor’s program counter.
INFO - Get information about the target system.

Some examples

QM> DIG
DIG00 PORTE:0 INPUT  HIGH
DIG01 PORTE:1 INPUT  HIGH
DIG02 PORTE:4 INPUT  LOW
DIG03 PORTE:5 INPUT  LOW
DIG04 PORTG:5 INPUT  LOW
DIG05 PORTE:3 INPUT  LOW
DIG06 PORTH:4 INPUT  LOW
DIG07 PORTH:3 INPUT  LOW
DIG08 PORTH:5 INPUT  LOW
DIG09 PORTH:6 INPUT  LOW
DIG10 PORTB:4 OUTPUT HIGH
DIG11 PORTB:5 INPUT  HIGH
DIG12 PORTB:6 INPUT  LOW
DIG13 PORTB:7 OUTPUT LOW
QM> USART
UDR0---->C6-->00 00000000 0:lo      1:lo      2:lo      3:lo      4:lo      5:lo      6:lo      7:lo
UCSR0A-->C0-->62 01100010 0:rxc0    1:TXC0    2:UDRE0   3:fe0     4:dor0    5:upe0    6:U2X0    7:mpcm0
UCSR0B-->C1-->98 10011000 0:RXCIE0  1:txcie0  2:udrie0  3:RXEN0   4:TXEN0   5:ucsz02  6:rxb80   7:txb80
UCSR0C-->C2-->06 00000110 0:umsel01 1:umsel00 2:upm01   3:upm00   4:usbs0   5:UCSZ01  6:UCSZ00  7:ucpol0
UBRR0L-->C4-->10 00010000 0:lo      1:lo      2:lo      3:HI      4:lo      5:lo      6:lo      7:lo
UBRR0H-->C5-->00 ----0000                                         4:lo      5:lo      6:lo      7:lo
QM> TMR1
GTCCR--->43-->00 0-----00 0:tsm                                                       6:psrasy  7:psrsync
TIMSK1-->6F-->00 --0--000                     2:icie1                       5:ocie1b  6:ocie1a  7:toie1
TIFR1--->36-->2F --1--111                     2:ICF1                        5:OCF1B   6:OCF1A   7:TOV1
TCCR1A-->80-->01 0000--01 0:com1a1  1:com1a0  2:com1b1  3:com1b0                      6:wgm11   7:WGM10
TCCR1B-->81-->03 00-00011 0:icnc1   1:ices1             3:wgm13   4:wgm12   5:cs12    6:CS11    7:CS10
TCCR1C-->82-->00 00------ 0:foc1a   1:foc1b
TCNT1L-->84-->86 10000110 0:HI      1:lo      2:lo      3:lo      4:lo      5:HI      6:HI      7:lo
TCNT1H-->85-->00 00000000 0:lo      1:lo      2:lo      3:lo      4:lo      5:lo      6:lo      7:lo
OCR1AL-->88-->00 00000000 0:lo      1:lo      2:lo      3:lo      4:lo      5:lo      6:lo      7:lo
OCR1AH-->89-->00 00000000 0:lo      1:lo      2:lo      3:lo      4:lo      5:lo      6:lo      7:lo
OCR1BL-->8A-->00 00000000 0:lo      1:lo      2:lo      3:lo      4:lo      5:lo      6:lo      7:lo
OCR1BH-->8B-->00 00000000 0:lo      1:lo      2:lo      3:lo      4:lo      5:lo      6:lo      7:lo
ICR1L--->86-->00 00000000 0:lo      1:lo      2:lo      3:lo      4:lo      5:lo      6:lo      7:lo
ICR1H--->87-->00 00000000 0:lo      1:lo      2:lo      3:lo      4:lo      5:lo      6:lo      7:lo
QM> PORTB
PINB---->23-->30 00110000 0:lo      1:lo      2:HI      3:HI      4:lo      5:lo      6:lo      7:lo
DDRB---->24-->97 10010111 0:HI      1:lo      2:lo      3:HI      4:lo      5:HI      6:HI      7:HI
PORTB--->25-->10 00010000 0:lo      1:lo      2:lo      3:HI      4:lo      5:lo      6:lo      7:lo

The PER command shows the defined "peripherals" (really a collection of related IO registers), each of these can be used as a command as shown above.

QM> PER
-->PORTB
-->PORTC
-->PORTD
-->TMR0
-->TMR1
-->TMR2
-->SPI
-->USART
-->TWI
-->AC
-->ADC
-->EEPROM
-->MCU
QM> IO
PINB---->23-->30 00110000 0:lo      1:lo      2:HI      3:HI      4:lo      5:lo      6:lo      7:lo
DDRB---->24-->97 10010111 0:HI      1:lo      2:lo      3:HI      4:lo      5:HI      6:HI      7:HI
PORTB--->25-->10 00010000 0:lo      1:lo      2:lo      3:HI      4:lo      5:lo      6:lo      7:lo
PINC---->26-->00 --000000                     2:lo      3:lo      4:lo      5:lo      6:lo      7:lo
DDRC---->27-->AA --101010                     2:HI      3:lo      4:HI      5:lo      6:HI      7:lo
PORTC--->28-->00 --000000                     2:lo      3:lo      4:lo      5:lo      6:lo      7:lo
PIND---->29-->03 00000011 0:lo      1:lo      2:lo      3:lo      4:lo      5:lo      6:HI      7:HI
DDRD---->2A-->00 00000000 0:lo      1:lo      2:lo      3:lo      4:lo      5:lo      6:lo      7:lo
PORTD--->2B-->00 00000000 0:lo      1:lo      2:lo      3:lo      4:lo      5:lo      6:lo      7:lo
TIFR0--->35-->06 -----110                                                   5:OCF0B   6:OCF0A   7:tov0
TIFR1--->36-->2F --1--111                     2:ICF1                        5:OCF1B   6:OCF1A   7:TOV1
TIFR2--->37-->07 -----111                                                   5:OCF2B   6:OCF2A   7:TOV2
PCIFR--->3B-->00 -----000                                                   5:pcif2   6:pcif1   7:pcif0

list cut for brevity
QM> P 200

        00-01-02-03-04-05-06-07-08-09-0A-0B-0C-0D-0E-0F
 0200:  20 49 50 43 5B 00 00 00 00 02 0A 02 67 65 64 20     IPC[.......ged
 0210:  74 6F 20 00 6C 65 64 00 74 42 43 44 45 46 47 48    to .led.tBCDEFGH
 0220:  49 4A 4B 4C 4D 4E 4F 50 51 55 52 53 54 56 57 58    IJKLMNOPQURSTVWX
 0230:  59 5A 00 2B 01 49 50 43 20 73 63 72 61 74 63 68    YZ.+.IPC scratch
 0240:  20 52 41 4D 00 01 00 00 00 00 64 07 4E 08 66 08     RAM......d.N.f.
 0250:  02 07 30 07 58 07 16 07 43 1E BD 6D 01 17 32 65    ..0.X...C..m..2e
 0260:  01 17 C5 6D 01 11 00 00 00 00 00 00 00 00 00 00    ...m............
 0270:  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
        00-01-02-03-04-05-06-07-08-09-0A-0B-0C-0D-0E-0F

I think that's enough for now. If there's any interest I can post more details.

This is currently at about alpha state so not suitable for beginners to play with, but if want to have a look I can clean up and post the code.


Rob

As usual for my threads there's no replies =(

Maybe I should have asked about using a '595 to multiplex some LEDs, we talk for days about that, then repeat the process a couple of days later :slight_smile:

Anyone heard of Parkinson's "Garden Shed" principle?


Rob

Rob,
Just saw your post. Makes available a lot of data about the state of the uC.
More than I would know how to take advantage of at the moment.
Robert

More than I would know how to take advantage of at the moment.

I suspect that's the case for most people, but let's take a typical scenario.

Q: I send a character to my Arduino and the program hangs.
A: Run the PC command a few times to see what piece of code is being executed.

or

Q: I'm copying a string into X but it doesn't print.
A: You dump the memory at X and see a \0 is the first byte, your string pointer had been incremented once to often before the copy


Rob

Any plans to support the original Arduino Mega or does the 2560 support the 1280?

Any plans to support the original Arduino Mega or does the 2560 support the 1280?

Yes, the only difference is the memory size AFIAK so the current code will work, just change the RAMEND #define.


Rob

Hi,

Could you post the code ? so I can have a chance to play with it.

As previous said what to do with all this info that can be produced. This is the type of tool that needs a manual / web page with cases. Like how you can see that a for loop goes one element too far etc (not the best example I know). More important one must have quite a detailed insight of how the low-level Arduino works - Data registers, ports , timers interrupts etc. I still don't have (taken) time to read the 500+ Atmel datasheet so a short 20 page "Advanced Arduino" booklet, or "Arduino under the hood", would be a good companion for a tool like this.

Here's the current source code.

quubmon_client runs on the debugging Arduino, talk to it via USB to a terminal
quubmon_server runs on the target Arduino, also includes a simple application

Currently the defines set the client to run on a 328 and debug a 2560

I've been developing the client software with a makefile outside the IDE and it works just fine, but I thought I'd run it through the IDE before posting and I'm having problems. It takes 5 minutes to compile then produces a bogus error at a bogus line. I'll try to figure this out but meanwhile you can look at the code, and it may not happen on another system.

Note that the useless-looking "#if 1" blocks are to allow code folding of sections in my editor.


Rob

quubmon_client.pde (92 KB)

quubmon_server.pde (9 KB)

"a bogus error at a bogus line"

Rob,
I saw the same thing in sketch I was helping pitchoilcan debug.
A comment line had lost a / along the way, was showing as a weird error somewhere esle.
There were also a bunch of #define variable 0; type lines, and then later on variable = analogRead(pin); that was causing errors.

Yeah I've had a good poke around for all the usual culprits that show up 300 lines later. Can't see anything.

The thing is that exactly the same code compiles just fine with my makefile, so there isn't any normal syntax errors. Maybe a different warning level in the compiler options, but then it's an error, not a warning.

The errors are

sketch_mar04a:14: error: variable or field 'PrintRegValUsingMask' declared void
sketch_mar04a:14: error: 'reg' was not declared in this scope
sketch_mar04a:14: error: 'r' was not declared in this scope
sketch_mar04a:14: error: expected primary-expression before 'val'

Now line 14 is part of a comment block at the top of the code.
The 'PrintRegValUsingMask' function is as follows

void  PrintRegValUsingMask (reg *r, byte val) {
etc etc
}

and struct reg

typedef struct reg {
	unsigned int address;
	char name[8];
	char bits[8][9];
};

So I'd say my reg struct is not being seen or bad somehow.

It's got me stuffed.


Rob

I don't suppose its something simple like putting a space afte void?

voidPrintRegValUsingMask -> void PrintRegValUsingMask

seemed to paste into this message with a tab in between
"void PrintRegValUsingMask "

No I just checked, the code is good, it's just something wrong with the cut n paste. (fixed)


Rob

I would love to try this out as well, but I get the same error.
First error is 'can not find Streaming.h'
Arduino 0021 and 0022 give the same error.
Where did you pick up Streaming.h and why did you include it?

Streaming can be got from here

http://arduiniana.org/libraries/streaming/

Sorry I should have put the link in the original post, I forgot I'd been using it.

why did you include it?

Because I hate having 10 Serial.print()s in a row. I much prefer

Serial << x << y << _HEX(z) << PadString (a, 8, '-') << endl;

There's still the compiling error under the IDE that I haven't been able to fix.


Rob

I've narrowed the error down to a few lines of code but cannot see the problem.

typedef struct reg {
	unsigned int address;
	char name[8];
	char bits[8][9];
};

void	PrintRegValUsingMask ((reg *)r, byte val) {
}


void	setup() {
}

void	loop() {
}

This produces the following errors with IDE 21

sketch_mar06a:7: error: variable or field 'PrintRegValUsingMask' declared void
sketch_mar06a:7: error: 'r' was not declared in this scope
sketch_mar06a:7: error: expected primary-expression before 'val'

I might start another thread about this to broaden the knowledge pool.


Rob

I saw this when I first started with the Arduino. Spent ages trying to figure it out. No idea why but typedefs of structs just didn't work. This change does work:

typedef struct reg {
	unsigned int address;
	char name[8];
	char bits[8][9];
};

void PrintRegValUsingMask(struct reg* r, byte val) {
}


void	setup() {
}

void	loop() {
}

Thanks sixeyes, I'm sure I tried that combination when I first had the error but maybe not.

For some reason I can't attach a new version of the client software now (there's a error with the forum that doesn't allow it) so change

void PrintRegValUsingMask (reg* r, byte val) {

to

void PrintRegValUsingMask (struct reg* r, byte val) {

Note that the client will run without a server Arduino being present but some commands will hang (I'm working on that).


Rob

The forum attachment problem has been fixed so here's a version of the client software that compiles under the IDE.

I'm busy designing some hardware at present but will get back to this soon.


Rob

quubmon_client.pde (92.2 KB)

Hi Rob,

I am very interested in your project.
I installed and tested the code that Nick Gammon posted (Thanks Nick) and was interested to try the additional features that you have implemented.
I am using two MEGA2560 boards and have connected them via the SPI pins (50 - 53).
Nicks' Code is working fine, so I am reasonably confident that my cabling is correct, but when I run your code the serial monitor reports:

QUUBmon v1.0
Compiled for
  Server: ATmega2560
  Client: ATmega2560
on Sep  2 2011

QM> Server offline.
QM> bad frame

I have confirmed that both Server and Client have the settings:

//#define RUNNING_ON_328
#define RUNNING_ON_2560

and have confirmed that the pins defined for SPI are 50 - 53.

Any suggestions of where I should start looking to debug it?

Cheers
Chris

I'm a bit rusty on this myself as I haven't used it for a while.

That #define you mentioned is on the server, there's also similar #defines on the client code, you should have them set as follows

#if 1 // SERVER and CLIENT selection
#define SERVER_ATmega2560
//#define SERVER_ATmega328	
//#define SERVER_ATtiny861
//#define SERVER_ATtiny84
//#define SERVER_ATtiny85

//#define CLIENT_ATmega328
#define CLIENT_ATmega2560

#define SERVER_C
//#define SERVER_ASM

#endif

See how that goes, I'll have a play with this here as well.


Rob