beginner needs help with digital outputs

Hi all,

At work I recently was tasked with learning how to program the Rabbit 2500 and 2600. I’m an Electrical Engineering undergrad and have taken a semester of C++ so I’m familiar with the language, but don’t have any experience with microcontrollers.

I’ve been reading the Dynamic C User Manual and the Rabbit 2500 User Manual to learn about the specific function calls, and I’ve been looking at example source code as provided by the Dynamic C IDE installation.

At this point I am a bit familiar with the language but am having a hard time understanding how exactly to properly write code that will change the states of the digital outputs. What I’d like to do, just as a learning exercise, would be to write code that would turn on a single Dig Out channel for a specified amount of time, then turn it off for a specified amount of time. After I do this, I’d like to change the entire bank, and then channels individually.

Where I’m running into problems is the actual code itself; the examples go from very basic stuff using the STDIO window that I totally understand to way complex code that I can’t even begin to comprehend…DIGIN and DIGOUT are way over my head because there doesn’t seem to be any stepping stone to get there. In theory I know what to do…I will use digout() and digbankout() and specify values. How to actually use these functions in real code is what I’m confused about. Do I call these functions in main() whenever I need? Do I have to define what they do outside of main() and then call them? I’m looking through examples but am having a hard time wrapping my head about how to actually write code from scratch.

If anyone could help me out I’d appreciate it. If I could see code that would just put a simple square wave on an output channel I think I could go from there and extrapolate what I wanted to do. I’m just confused on how to call functions properly in main() and what I need to define above main().

Thanks for any help!

–Phil

Ok, so I figured out how to hack the sample code for flashing the LEDs on the 2500 board, changed a few things, and was able to get the code to compile so that it should be turning the digital outs on and off instead of the LEDS. The strange thing, now, is that when I measure the voltage on the digital outputs it’s turning on and off but only changing from 0VDC to 0.010VDC for high. This is obviously not working since my high should be around 3.3VDC, right? I’ll put the code below and I would very much appreciate any help with this issue. Am I missing something?

Thanks for any help,

–Phil

//early test for dig out experimentation; turn dig0-dig7 on and off at a user
//defined rate. so far dig out only goes to 0.010VDC when “high”,
//a high value should be in the ballpark of 3.3VDC

#class auto

#define ON 1
#define OFF 0
#define DOUT0 0
#define DOUT1 1
#define DOUT2 2
#define DOUT3 3
#define DOUT4 4
#define DOUT5 5
#define DOUT6 6
#define DOUT7 7

cofunc digout_try[8](int channel, int ontime, int offtime)
{
for(;:wink:
{
digOut(channel, ON);
waitfor(DelayMs(ontime));
digOut(channel, OFF);
waitfor(DelayMs(offtime));
}
}

main()
{
brdInit();

for(;;)
{
  costate
	{
		wfd
		{
  		digout_try[0](0,150,150);
        digout_try[1](1,150,150);
        digout_try[2](2,150,150);
        digout_try[3](3,150,150);
        digout_try[4](4,150,150);
        digout_try[5](5,150,150);
        digout_try[6](6,150,150);
        digout_try[7](7,150,150);
     }
   }

}
}

augh…sinking outputs. n/m, i figured that part out.

Hi all, new to rabbit processors here, and surfed into this thread to see how this thing worked.

I am particularly intrigued by this program, first off, it works,
(with the addition of the line
digOutConfig(DIGOUTCONFIG);
)

but secondly it uses what appears to be an array of functions ( cofunc digout_try[8](int channel, int ontime, int offtime), note the [8].) This is a new concept to me, I have not seen this in C before, can someone explain a bit more? This is a concept that exists only in Dynamic C?

This code is specific to an extension to the C language that Dynamic C adds. This is called a cofunction and allows you to implement cooperative multitasking within your code with a minimum of effort.

A cofunction is in most ways a normal C function, with the exception that certain statements within the function can relinquish control, while making note of where that occured so the next time the function is called it can pick up where it left off. The statements that do this in the example given are the waitfor(…) function calls in the digout_try cofunction. The waitfor function is a special function used within costatements and cofunctions. When first encountered, it sets up a timer for a given number of milliseconds, then releases the processor to handle other tasks. If the function is called again before the time has elapsed, it will again release the processor to do other things. When the time has elapsed, then the function will resume processing at the statement after the expired waitfor call.

So why the ‘array reference’ between the function name and the parameter list?

Each individual cofunction can usually only be called once within a costate statement. This is because a cofunction has an internal data structure which is setup to track the state of the function (where to resume, beginning timestamp of active waitfor delays, etc.). The array notation allows you to create multiple instances of the cofunction, each with its own data structure. This way the same function code can be called 8 times within the costate statement, each with its own state information. So even though it may look like the outputs would be processed one at a time, all 8 will be toggling at the same rate of 3.33Hz.

[QUOTE=bsprouse;4325]This code is specific to an extension to the C language that Dynamic C adds. This is called a cofunction and allows you to implement cooperative multitasking within your code with a minimum of effort.

A cofunction is in most ways a normal C function, with the exception that certain statements within the function can relinquish control, while making note of where that occured so the next time the function is called it can pick up where it left off. The statements that do this in the example given are the waitfor(…) function calls in the digout_try cofunction. The waitfor function is a special function used within costatements and cofunctions. When first encountered, it sets up a timer for a given number of milliseconds, then releases the processor to handle other tasks. If the function is called again before the time has elapsed, it will again release the processor to do other things. When the time has elapsed, then the function will resume processing at the statement after the expired waitfor call.

So why the ‘array reference’ between the function name and the parameter list?

Each individual cofunction can usually only be called once within a costate statement. This is because a cofunction has an internal data structure which is setup to track the state of the function (where to resume, beginning timestamp of active waitfor delays, etc.). The array notation allows you to create multiple instances of the cofunction, each with its own data structure. This way the same function code can be called 8 times within the costate statement, each with its own state information. So even though it may look like the outputs would be processed one at a time, all 8 will be toggling at the same rate of 3.33Hz.[/quote]

Bill,

Excellent explanation thank you. I did remember reading about the re-entrant problems with cofunctions in the Dynamic C user guide. Its quite clever how Dynamic C (DC) makes use of the waitfor, yield, abort, commands to pass control between the cofunctions. The “array of co-functions” really took me by surprise though. Actually I was scratching my head on why DC even has a problem with multiple instances of a function in the first place. Seems to me it is deterministic that the programmer has defined the different instances of the functions clearly. And part of the creation of the instance should make a local copy internal data structure (much in the same way a recursive function would use the heap to make additional copies of its local variables)

Its not a big deal, and the array of functions is a very clever way around it.

two+ questions though,

  1. if the co-function is more complicated and say calls another function say foo(a,b,c); haven’t we just created that situation that the restriction is trying to prevent? Also within foo(a,b,c), will it release control to the other other cofunct’s?

  2. on the focus release functions, waitfor, abort, yeild, what about file io (aka printf, fprintf?) these are typically functions that are very timely yet I wouldn’t want a printf statement in mycofunct[0] intermixed with the parallel printf statement in mycofunct[1] any idea how this is handled?

Sincerely,

Jon

This is not a problem if you’re calling normal C functions, at least as far as execution. Both foo and printf are normal C functions. There is never a chance that control is given up part way through a printf call as a printf call is not a cofunction, and therefore will always run until completion. Understand that cooperative multitasking is not like pre-emptive multitasking. It never steals the processor away from a normal C function, it only gives up the processor when executing a waitfor or yield statement within the cofunction. Obviously, this means that a printf within your cofunction could certainly wreak havoc with the expected 3.33Hz cycle rate of the outputs.

Now nesting of cofunctions would be a problem, and that is why it is not recommended, even in simpler situations. It definitely should NEVER be done in a multi-instance cofunction.

“this means that a printf within your cofunction could certainly wreak havoc with the expected 3.33Hz cycle rate of the outputs.”

One of my tasks with the rabbit is to monitor 3 UARTS and stream the data into a single outbound UART and copy this data to a compact flash card file (using the bl4s200) I was planning on using the cofunction to read, retransmit, and write to the file, is this possible given the above “havoc” warning? I figured with the relative slow speeds of UARTs (4800bps for a GPS unit, 115200 for the other RS232 devices) this wouldn’t be an issue but now you have me worried.

This would be a concern if you were managing the serial ports in the very simplistic way that these ports are being toggled in the sample code (samples are just that, samples, not necessarily the optimum way to do something). But luckily, you have pre-written serial drivers using interrupts and definable circular buffers at your disposal. Interrupts can steal the processor from either C functions or cofunctions, so all you have to do is make sure you define your buffer large enough to hold whatever data could be received between your worst case timing between servicing of the buffer.

It is very common in real time systems to have buffers between background and foreground functions. This allows the foreground functions to use longer functions such as printf without disturbing the high-speed background operations. The sample where I made the ‘havoc’ warning could easily be re-written using interrupts to allow the foreground use of a printf function. Often, the timing done in costatements is not overly critical. In other words, the only side you need to guarantee is the delay before initiating the next step. If the initiation of the next step is delayed a little further, this is not really a problem. With control mechanisms this is often the case. I only brought up the issue with long function calls so that you realized that waitfor does not guarantee the processor is available exactly when the delay ends, only that the following statement is held off by at least the delay time. This is important to understand when using costatements.

Thanks again Bill for an excellent discussion. I’m away from my rabbit for a few days, but I’m looking forward to implementing the Uart, then the multiple uarts with circular queues, and so on. I haven’t gotten that far yet. I imagine I’ll be back again but first I’ve got a bit of homework to do.

  • Jon