Software architecture using C for mid-range PIC.

Apologies. I based my assumption on: switch((u16)buf[0]

Well, I'm stuck with it. Unless the C18 is *so* bad that I can make a case for the client spending more money. Any opinions here on how the C18 measures up?

I am in no way allergic to anything that will save coding time - but I do worry about how much code space, RAM and CPU cycles general purpose tools will consume.

Happy to lose points if I gain time!

Reply to
Fevric J. Glandules
Loading thread data ...

If your protocol is simple, e.g. "command arg1 arg2 ..." newline "command arg1 arg2 ...", I would just start with something like Rocky described:

void hello(void) { // you can parse command arguments here printf("hello "); }

void world(void) { printf("world!"); }

typedef void(*CommandFunction)(void);

struct Command { char* name; CommandFunction function; };

struct Command commands[] = { { "hello", hello }, { "world", world } };

void evaluate(char* commandName) { int i; for (i = 0; i < sizeof(commands) / sizeof(struct Command); i++) { struct Command* command = &commands[i]; if (strcmp(command->name, commandName) == 0) { command->function(); return; } } printf("command not found: %s\n", commandName); }

int main(int argc, char** argv) { evaluate("hello"); evaluate("world"); evaluate("foo"); return 0; }

If this is too slow, sort the commands alphabetically and use a binary search.

For most projects C18 produces code which is fast enough. Don't worry about speed until it is too slow :-) E.g. if you have a 100 ms measure cycle, it doesn't matter if a function needs 100 us or 1 ms and writing code which is easy to read and to maintain is more important.

--
Frank Buss, fb@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
Reply to
Frank Buss

The C18 compiler will compile your construct but will generate a lot of instructions to handle it. The PIC architecture does not have a bunch of general registers for C18 to use for register allocation, it only has an accumulator (the W reg) and a few other registers you can use.

The free C18 compiler does not do sub-expression elimination and some other common optimization techniques but does generate reasonably tight code. It wont beat carefully crafted assembler but I know of only

3 or 4 compilers I've ever run into that could beat hand generated assembler for code density. You will generally find that the 2K SRAM is enough. I've had some pretty big projects using serial, USB, driving LEDs and relays along with a bunch of other stuff and not used more than 1000 to 1200 bytes of SRAM. The IDE has some tools to help you watch memory usage.

Lookup tables, constants, etc can be forced into flash locations to reduce runtime SRAM requirements. But you suffer a hit having to do a flash read. Since you are new to PIC, carefully study the manual regarding the various run time libraries, pay close attention to the string functions, memory functions and printf. There are different flavors depending on if the source (or destination) is in flash.

I have also found that the default IDE libraries are compiled for 24 bit pointers and you suffer a hit with this. They work but you have to make sure your code memory model matches the library's LARGE model. Anytime I load the IDE I recompile the libraries with the SMALL memory model which gives me 16 bit pointers. This works for all the low end PICs that have less than 64K of flash.

--
Joe Chisolm
Marble Falls, Tx.
Reply to
Joe Chisolm

In practice, accurate timing is only required in multidrop slaves. Multiple PCs are seldom used as slaves on the same RS-485 bus.

When the PC acts as a Modbus master or a point-to-point slave, the connection works well with conservative timing, although there might be a few performance in throughput.

Paul

Reply to
Paul Keinanen

Sorry, but must disagree :-). The problem with the above is that you still have inband data embedded in the code. The only way to make the code completely reusable is to separate form and function. In this case, all the parser needs to know about is the *structure* of the data, not it's content.

I would rewrite the code to allow this:

eStatus = eParseExec (&sRootCommandNode);

Where sRootCommandNode is the command parser table root and the command functions are called via the table contents. It might seem a trivial change, but can have a major impact w/regard to future maintenance and spec change.

The command parser is completely encapsulated and can be replaced in the same application if the command format changes. Being encapsulated, with no global data, it's easy to make it into a library module. After all, who has the time to rewrite the same stuff over and over again ?.

Taking the time to design good data structures is worthwhile, imo and is the key to a robust design...

Regards,

Chris

Reply to
ChrisQ

I tend to use a command function that returns an integer/byte (depending on architecure). Reason being if you return an error code you can do some common error reporting for the parsing such as using return values for

0 Success 1 first argument missing ... 'n' max argument number missing 0x81 first argument invalid 0x8n max argument invalid 0xFF hardware failure I normally make the first command tried a 'help' command to list in short form valid commands accepted, and two other commands to return strings of product name and software version. These of course normally return no errors. This way you prove the structure of the code before proving the more complicated commands.

....

or error = command->function(); // insert common argument function error handling here

--
Paul Carpenter          | paul@pcserviceselectronics.co.uk
    PC Services
 Timing Diagram Font
  GNU H8 - compiler & Renesas H8/H8S/H8 Tiny
 For those web sites you hate
Reply to
Paul Carpenter

Even if you want to use C, may I suggest FlashForth, a 16 bit Forth Operating System for the PIC18/PIC30/soonPIC24. It has an inbuilt command interpreter and compiler. It also has an round robin multitasker allowing you to have background tasks in addition to the operator task. Forth code for I2C is provided as an example.

With the compiler you design new command langauges to your liking. These new commands can then interpreted by the interpreter.

formatting link

-- Mikael

Reply to
Mikael Nordman

If you can live with out an RTOS. Mature tools, lots of fourms, lots of code samples, A bigger selection of parts, dirt cheap. Sometimes a cheap lame CPU fits the bill.

Reply to
Neil

Or you could use bit vatiables.

Reply to
Neil

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.