BoostC Forum Extracts 2007

From OpenCircuits
Jump to navigation Jump to search

Almost Ready For Reading[edit]

A macro like MAKESHORT can initialize a variable but the compiler does not know that and generates a warning. Is there a way to solve this without initializing the variable explicitly?

    u16_t timestamp;

    t1con.TMR1ON = 0; // stop timer
    MAKESHORT(timestamp, tmr1l, tmr1h);

    en_of_pulse = timestamp; <<==== causes warning

It's not the macro that's the problem, but the inline assembly it uses. The compiler doesn't notice if you set a variable with inline assembly statements and warns that it's possibly uninitialized. Declaring the variable as 'volatile' gets rid of the warning, but isn't a great solution as you might miss a true 'uninitialized' case.

I am not an expert, but I think I have seen compilers that have pragma's that give hints to compiler about these things.

initializing struct[edit]

Problem initializing struct. Whah, this doesn't work!

typedef struct {
    char foo[11];
    bar_enum bar;
} baz_list;

baz_list baz[] = { "0123456789", quux,
                   "0123456789", quuux,
                   "0123456789", quuuux
                 };

I can create a two dimensional array of strings and initialize them or a array of enums and initialize them but not an array of structs.

A more premitive question to ask would be why:

CODE
struct thing {
  char ch_1;
  char ch_2;
};
 
struct thing thingy = {2,2};

doesn't work.

I believe you're going to have to assign the values yourself. I'd say use an inline function or something to make it look neater:

struct thing {
  char ch_1;
  char ch_2;
};

inline void set_thing( struct thing &i_thing, 
                       unsigned char ch_1, 
                       unsigned char ch_2 ) {
  i_thing.ch_1 = ch_1;
  i_thing.ch_2 = ch_2;
}

void main( void ){
  struct thing i_thing[3];
  set_thing( i_thing[0], 2, 3 );
  set_thing( i_thing[1], 5, 3 );
  set_thing( i_thing[2], 1, 9 );

Found the thread - http://forum.sourceboost.com/index.php?showtopic=3404


function prototypes[edit]

    • Question 1:

Function prototypes, It looks like they are allowed, but not required nor enforced?

Prototypes are required if you do a forward reference to a function. If you are in the habit of using them, then always use them. I do.

delay timer[edit]

    • Question 2:

If I call

 delay_ms(1000 ); 

I get no warnings. Is there a way to make it more strict?

If you go to Settings - Options and enable All warnings the compiler will warn you if you exceed 255 for a delay.

interrupt handlers[edit]

    • Question 3:

Interrupts; If I don't put the interrupt function in my code, is there a default handler?

There is no default interrupt handler that I can see. Keep GIE = 0 if you don't want you program to go into the woods.

    • Question 4:

Global variables vs volatile; If I declare a variable in a header file, and wish to use it in both a main thread function and an interrupt handler, do I really need to declare it volatile?

If I was sharing a variable with main and interrupt, I would probably make it volatile. It all depends on how your main code is written and how many times the variable is used in main. The compiler may retain the variable value between uses and the interrupt may change its value between uses. You could always devise a semaphore type system.


location of variables in memory[edit]


I had some code that suddenly got bigger and slower and all I'd done was change the size of an array, though no variables ended up placed anywhere but bank 0. ...

read the post for some info an location of variables in memory, bank switching ..... size and speed.



Boostc gives me the warning Caution: Delay inaccurrate: 'delay_us', Delay overhead:0.01ms, Unit delay:0.001ms

How do I interpret the overhead and unit delay....?

delay_us( 1 ) gives 0.01ms + (1 * 0.001ms) = 11us delay_us(12) gives 0.01ms + (12 * 0.001ms) = 22us delay_us(13) gives 0.01ms + (13 * 0.001ms) = 23us

delay_us(0) results in 0.01ms + (255 * 0.001ms) = 265us



notes that I am not able to summarize about structs union and access of sub-components, you need to read this yourself.



Best Method For Accumulated Timer -- Go read it for more info.



May be useful for lcd read and other purposes, I cannot summarize. Go read it for more info.


more[edit]


How do i measure the eact timing on my code using boostc?

Set breakpoints in the debugger at the beginning and end of the code you want to evaluate. in the debugger you can see the amount of ticks. so when you let it run from breakpoint to breakpoint you are able to see how manny ticks it took. If I don't oversee something here ( ) this should be a working method to determine the exact time it takes to run that peace of code.....

A tick appears to be an oscillator cycle. If you step through a 1 cycle instruction it will increment the tick count by 4. A 4MHz xtal will give 1us instruction cycle time.

The tick count will change to values in 'kilo' after a while i.e. 10k etc. which cannot be reset to zero.

More exact timings come with using the StopWatch Plugin, get it if exact timing of code is needed.

If you install BoostC within MPLab (Microchip IDE) you can use its watchdog feature measure in real time.



As has been pointed out, you should have i != 100 and i++. But in general, it's said to be safer to use "<" than "!=" in such a loop as it can prevent infinite loops if the "i" gets changed somewhere else in the loop.

If you KNOW that the loop is going to be executed at least once, you are better off using the following:

 i = 0;
 do { /* loop contents */ } while ( ++i != 10 );

Or if "i" is ONLY used as a counter, the following can be better still:

 i = 10;
 do { /* loop contents */ } while ( --i != 0 );

Both can produce shorter, faster code!



You can't cast rom to not-rom types or vice versa. I'd either do 2 switch constructions: one for rom and another for not-rom arrays or use a buffer where rom arrays will be copied before use.

Regards,

New to C and I may be missing it, but I think assignment it the wrong way to go, instesad use a string copy to move from rom to ram. I know this sor of thing works because I do it all the time.

Russ

initializing struct[edit]

I have a structure:

    typedef struct 
    {
    unsigned int A; 
    unsigned int B;
    unsigned int c;
    } ConvertCoeff;

and I declare an array of this structure:

    ConvertCoeff coeff[8];

As long as I leave it this way everything is OK. But if I try to intialize the array during decleration as follows:

    ConvertCoeff coeff[3] = { {1,2,3}, {1,2,3}, {1,2,3}};

I get an error during compilation - missing semicolon. Is it not a legitimate initialization? I know it is possible on other compilers - how do I do it in BoostC?

It apears that BoostC does not like initialising structures like other compilers. You will have to fill your structure the hard way.


interrupt handlers[edit]

the linker generates a serious stack warning because I have a function which is called within the handling of a rb0 interrupt and also in the program main loop. I can imagine that this can cause problems when the function is called by the interrupt routine and within the main() loop at the same time.

But under specific conditions the rb0 interrupt handler (which contains that function call) is disabling it's interrupt and activates a flag. Depending on that flag the mentioned funtion is called in the main loop.

So that function, referred to in the warning, can never be called in the interrupt routine at the time it´s also being executed because of a call within the main loop!

This is still all tricky or it´s not a problem to ignore this warning under this conditions? If you are sure you are handling this situation correctly you can ignore this warning, your code looks like it maybe ok, but this kind of code can be tricky to understand.


delay timer[edit]

Yes, this one bit me too! I wrote the following routine that you can use for any ms value from 1 to 65535. I timed it at 60,000 and it seems to be pretty much on the money.

 void delayMs(unsigned int ms){
      char i;
      char high = ms >> 8;
      char low = ms & 0x00ff;
      for(i = 0; i < high; i++){
           delay_ms(255);
      }
      delay_ms(low); 
 }

You might think that it needs another delay_ms(1) in the loop but I got the most accurate time without it.



Is it possible for lprintf to write a substring to the lcd?

eg. I've got a string 254 bytes long, but I only want to print 16 chars to the first line of the display.

I tried lprintf("%c",buffer[i]) in a for loop, but that didn't work (no compiler error though).


...
    lcd_datamode();
    char c, i;
    for( i = 0; i < 16; i++ )
    {
        c = buffer[i];
        if( c == 0 ) 
            break;
        lcd_write( c );
    }
...




That's it. Adding -d DEBUG to the compiler options does exactly what I want. Thanks very much.

Edward





EEProm Data[edit]

Is there a way to fill data to an address relative to _EEPROM like:

    #pragma DATA _EEPROM,     1, 2, 3
    #pragma DATA _EEPROM+10,  1, 2, 3
    #pragma DATA _EEPROM+20,  1, 2, 3


because the preprocessor doesn't seem to accept this one

No this is a limitation Have a look at where _EPROM is defined, use this address manually adding the required offset.



Plugins[edit]

Q: Tried the LCD display plugin with the sample picdem2+ project. Built ok, but when I run it in debug mode, the lcd window disappears?

A: IDE has 2 layouts: for edit and for debug modes. It seems that you opened the lcd plugin when debugger was in edit mode but when you starte debugging ide uses its debug mode layout that does not have this plugin open in there. Just open the ldc plugin while debugging.



Asm Optimizations[edit]

Is possible to turn off all the optimizations within the ASM code. Well, i need to make some very time paced routines that jump into different tables and output it on different pins. But now BoostC compiles in my ASM code all the different bank switching instructions.

Does anybody know if it is possible to turn off all the optimizations? (off course then you have to know exactly what you're doing!) Otherwise it would be a neat enhancement.

Btw: The "goto $+1" seem very stupid for a c compiler, but it would be neat if that's possible somehow. I even tried

 _asm{
      goto label
      label:
 }

Use:

asm{
   goto label
   label:
}


Pointer to Functions[edit]

Q: Would like to know if BoostC supports pointers to function; are there any limitations or not?

A: Function pointers are supported since v6.70. See http://www.sourceboost.com/CommonDownload/VersionLog.html

Limitations: - As far as I know arrays of function pointers are not supported. - It seems that the call tree is not parsed through function pointers. So, function pointers should be used together with a software stack or -very carfully- with the hardware stack. See http://forum.sourceboost.com/index.php?showtopic=3279

what[edit]

last[edit]

16th October 2007 - 05:39 PM http://forum.sourceboost.com/index.php?showtopic=3301&pid=12469&mode=threaded&start=#entry12469

I have a project that needs to save alot of config data ect. The eeprom in the pic is not big enough to store all data: I have alot of free flash in the PIC can I use that to store data whit read and write to flash funtions? It will not be alot of writeing and read. Or should I use a external eeprom? Interested in advertising here? Contact support@sourceboost.com



1. The easiest is to store data in normal RAM using variables or an array. 2. However, I suspect you are referring to program memory (ROM) which can be written to when programming with the BoostC 'rom' command and read at any time. 3. If you want your PIC program to update this data on the fly you need to have a device which supports 'self-write' ('Enhanced Flash' versions in the 16F series or available in most or all? 18F's). Harder than 1 or 2. 4. External memory will be more work than 3. David.


gap[edit]

lot of material skipped, need to go back and fill in

start end of june -- merge

I2C[edit]

http://forum.sourceboost.com/index.php?showtopic=3168&pid=11895&mode=threaded&start=#entry11895


I'am trying to implement i2c master on a 16F946. It's possible to implement i2c in hardware with this device ?

Writting your own i2c drivers is pretty simple depending on the complexity you need. But basic interfacing is trivial. Depending on "canned" libraries is not always a good thing.

Inverting Serial Data[edit]

http://forum.sourceboost.com/index.php?showtopic=3160

Is there a method to invert the TTL serial input/output on the 16F877 in software or do I have to do it in hardware? I have an inverted TTL level signal that I need to accommodate.

If you are using a software UART then you can invert it with that software. If you are using the hardware UART you have to invert the signal externally (either with a single transistor or a TTL gate).


http://forum.sourceboost.com/index.php?showtopic=3161&pid=11889&mode=threaded&start=#entry11889

Hi. I can create and read an array created with the rom char statement. Is it possible to write to this array from within the program to use as a temporary data logging store (before writing to SD card)?

ROM objects can't be modified using C. The only option to do this is to use inline assembly (on targets that support run time flash write).

I want to minimise external components and the complexity that goes with that. This pushes me towards the 18F range where I can easily get up to 1k EEPROM and over 3k RAM. So I will go this route probably using RAM for caching since it is so much easier and quicker. Thanks for helping me think the options through.


Assembly optimized Out[edit]

http://forum.sourceboost.com/index.php?showtopic=3158&pid=11866&mode=threaded&start=#entry11866

Q: I been having problems with using inline asm, the some of my code being removed from the compiled output.

A: Change _asm to asm and then no dead code is removed.


LCD[edit]

http://forum.sourceboost.com/index.php?showtopic=3142&pid=11816&mode=threaded&start=#entry11816


I have a project that needs to drive 4 16x1 lcds ( I will be using a 16f73) . I have used the lcd_driver to control a single lcd, and it works very well. If I understand these things correctly I can bus the data and control lines (except the enable line) to all the lcds. Then just toggle the enable line for the lcd I wish to talk to.

If this is correct, my question is how do I setup the "#define LCD_ARGS" for more then one enable line? I would use the same PORTC, TRISC for all the control ports but not being that strong a 'C' programmer I'm unsure how to insert a variable port bit number into the template. Or do I have to redefine the whole thing?

Take the existing code and change it so that it instead of directly setting and clearing the enable ( e = 0; and e = 1; ) to call a function. This function can then be used to set and clear the enable of the required display. Doesn't look like too big a change.

Thanks for the pointer. I cloned the lcd_driver into my_lcd_driver and started by removing all the 4-bit functions. Cleared some extra rom space (a good thing). Added a function call for selecting the proper enable port. Now all I have to do is wire it all together.

In line Assembly[edit]

http://forum.sourceboost.com/index.php?showtopic=3141&pid=11809&mode=threaded&start=#entry11809


have a PIC18 device and I'd like to get the address of one of my C variables so I can use a pointer to it in inline assembly. I see in the manual that I can use "movlw _variable" to get the address in the W register, but to set the indirection registers I need 12 bits (8 for FSR0L, and 4 for FSR0H). "movlw _variable" just seems to me to get the lower 8 bits, how do I get the upper bits so I can set up the indirection registers properly?


    #include <system.h>
    int x;
    void main()
    {
     int* xAddr = &x;
    asm
    {
            MOVF _xAddr,W
     
            MOVF _xAddr + 1, W
     }
}


Using a simple underscore with the c variable name gives you access to the variable in asm for almost all compilers.


    int x = 2;
    
    asm MOVF _x,W



0----

http://forum.sourceboost.com/index.php?showtopic=3143&pid=11808&mode=threaded&start=#entry11808

Q: I have been using the rs232_driver with a pic16f628 on a couple of projects. My question is about including the #define MODE (USART_reset_wdt | USART_HW).

Is it a good idea to setup a wdt when using rs232? I had always just selected the USART_HW and let it go at that. But there have been a couple of times when my boxes would fail to respond and have to be rebooted. I have no idea what the problem was, as it only happened once or twice over months of use.


A: I think you can enable the watch dog timer. The #define MODE (USART_reset_wdt | USART_HW) will automatically clear your wdt before it resets. I think you might be facing some other problem & not related to wdt. See if your Rx buffers are overflowing and so receive disabled.

Actually you may want to check your pic frequency and the WDT timeout, if they are too close any extra small delay may randomly hose you if your frequency is not callibrated well. Remember even crystals have a +/- tolerance percentage and fluctuate with ambient temperature if they are not oven enclosed or compensated.

Interrupts[edit]

http://forum.sourceboost.com/index.php?showtopic=3138&pid=11798&mode=threaded&start=#entry11798


Hi. I have some questions about using interrupts please: 1. Is there any limit to how much code you can put in the interrupt function? 2. Interrupts have to be at address location 4. Does this limit how many functions/code size that can precede the interrupt function so I can call them from the interrupt? 3. Related to 2, how do I do function prototyping so I can call functions that are written 'after' the interrupt function? I'm a novice at programming but do have have many simple programs working successfully and can make basic interrupts work. More complex ones are causing me some grief hence my questions. Thanks, David.


2. Interrupts have to be at address location 4. Does this limit how many functions/code size that can precede the interrupt function so I can call them from the interrupt?


This is hardware-related. The idea of programming in C is to distance you from these hardware issues, though in the world of microcontrollers that distance is necessarily quite short! The Linker will sort it all out for you so the sequence of functions in the source code is immaterial and should be designed for ease of human consumption rather than for the hardware.


It may be difficult to work with interrupts in your case ( due to key bouncing). Why don't you try some thing like this.. Lets say you have connected the switch to portb.0 & based on the duration you have pressed you decide what activity to do.

<<<Lots of cdoe go back and read it >>>>

ADC Format[edit]

http://forum.sourceboost.com/index.php?showtopic=3129&pid=11777&mode=threaded&start=#entry11777

Q: I need a definitive answer to my one wire problem please. Regarding my previous posts on the subject, I'm still having no luck after using various methods. Will someone please tell me in what format the 'data' is returned after a temp. conversion. i.e. 9 bytes, bytes 0 & 1? etc....

The sensor is working regarding the s/ware and h/ware sides of it, but, I cannot work out how to use the data, (which returns as -1 and doesn't vary at all with temperature). With the lcd header file it can be opened and you can work out what is happening not so with the one wire header. Does it actually work? Has anyone proved it?

A: These devices (as per datasheet) can return all 9 scratchpad reads, of those only two are needed for minimal temperature reading. ( Two give you the basic plus, minus, leading integer values and either .0 or .5 )

Be aware if your american and i am remembering correctly, the values returned are in C not F.

For your reference: -Page 3 gives reference return values. -Page 6 gives you the description of all 9 scratchpad returns. http://pdfserv.maxim-ic.com/en/ds/DS1820-DS1820S.pdf


Q2: I realise (from the dallas data sheet) that 9 bytes are returned, however, the answer I need is what exactly does the return char 'data' in the 'oo_get_data' function contain as far as the sourceboost ide is concerned, bytes 0 & 1, which contain the temp. data or the full 9 bytes?

A2: oo_get_data() does exactly what one would expect it to do. It is a generic handler to take data off the onewire. This means it will return only the first byte if you just drop it in plain. For the Dallas sensor, you have to call it 9 times for all the bytes.

Volatile[edit]

http://forum.sourceboost.com/index.php?showtopic=3133&pid=11776&mode=threaded&start=#entry11776

Hi all, I am not new to C, but new to C on a PIC. I am using a PIC16F628. I have a function and whenever I compile it tells me that the function will never return. If I look in the asm file, all I see is a label and then a goto to that label. Here's what I have:

//This will send a byte over the serial port

    void SendByte( char b )
    {
         nop();
  
         //Wait for empty buffer
         while( !(test_bit( PIR1, TXIF )) )
         {
         }
  
    //Send the byte
    txreg = b;
    }

Change PIR1 (which is defined as a constant) to pir1 (which is define as a volatile variable). Because of the use of the constants with test_bit the code is optimised away.

I2C[edit]

http://forum.sourceboost.com/index.php?showtopic=3132&pid=11762&mode=threaded&start=#entry11762


I have a board with 3 PICs, a master 18F4525 and 2 slave 16F876s, connected on the I2C bus. I wish to use the hardware UARTs on the slave PICs as additional serial ports (as well as additional I/O) using BoostC 6.70. I cannot search the archives for "I2C" (too few letters) and all of the examples I've found deal with reading/writing to an external EPROM. Can I get the master PIC to directly access the RAM locations in the slave PICs?


You may have a look here : http://botzilla.free.fr/node10.html. Then if you google with "PIC I2C slave" you should find out many ideas, including a Microchip application note AN734.

I've found various bits of code I can patch together to hopefully do what I need.

Searching has also shown that there is an error in AN734 for Slave operation.


Interrupt Problems[edit]

http://forum.sourceboost.com/index.php?showtopic=3134&pid=11760&mode=threaded&start=#entry11760

In my project I am using 3 interrupt sources, they are tmr0, RB0/INT, ccp( capture interrupt) all as external interrupt on pulse. I have a problem with the ccp interrupt. The problem is every time there is some noise ( electrical disturbance from power line etc) the ccp interrupt gets disabled. I need to reset the system to get it to work again. I found that such noise ( as found in my present circuit setup) does not have any effect on the tmr0 or RB0/int interrupts. Right now i can do away with this problem by simply changing the interrupt source to tmr1 but my future projects may require more sources & so i would need a way to use them(ccp) reliably.

Has any one faced similar problems ? Can any one suggest some techique to use the ccp interrupt reliably?


Make sure you have a decoupling cap across the suppy lines entering you PIC. A 0.1uF ceramic seems to be the way to go. Put it as close to the pins as possible. By supply lines I mean betwen Vcc and GND.

Read Modify Write[edit]

http://forum.sourceboost.com/index.php?showtopic=3123&pid=11706&mode=threaded&start=#entry11706


Sorry for the short answers, first time the phone went and second time I got called away then got distracted.

Anyhow, it is almost certainly Read Modify Write, the fast A.0 blips on momentarily implies it is being written to and then overwritten by th enext instruction.

How does this work? A PIC has rather crude ports compared to other processors, a read always reads the state of the port pins a write always writes to the output register. Instructions that modify SFRs read the SFR into a hidden reg, modify the hidden reg and write back to the SFR, when this happens with a port it is the pins that are read and the result written back to the out put which causes the error you see.

PIC 18 have an extra register per port to help with this problem.

A solution is to keep an image of the output, modify the image and write that out to the port EG char aImage; aImage = 0; porta = aImage;

... .. aImage.0 = 1; aImage.2 = 1; porta = aImage; ... aImage | = 3; porta = aImage;

of course PORTA has further complications due to being set to analogue at reset.

Another solution is to use a proper processor... whoops...how did that slip out?


http://forum.sourceboost.com/index.php?showtopic=3118&pid=11696&mode=threaded&start=#entry11696

What Is "label" Part Of #pragma Data Used For?		Options 
 

The "label" part of the pragma statement allows quoted character string to be specified. The characters of the string are converted into data bytes by the compiler. This is one way string data can be stored in ROM on a PIC18.


Discussion of software and hardware usart issues[edit]

http://forum.sourceboost.com/index.php?showtopic=3114&pid=11681&mode=threaded&start=#entry11681

Discussion of software and hardware usart issues

I am currently working on a project in which the pic is made to read adc values from an external adc chip. The adc chip outs the data in a bcd format (-20,000 to +20,000 counts) & it generates 5 strobe pulses during which it outs the 5 digits of its adc result. Using ext interrupts i load these value into the pic. Simultaneously I am reading a rotary positional encoders output again thro' ccp interrupts . The value of the adc or the encoder is displayed on to 6 no. of 7-segment led display which are multiplexed on to 8 i/o pins. Now i also need to transmit the adc and encoder values thro' rs232 to a PC.

As you can see my interrupt routine is heavily loaded. What i need to know is if i use the emulated(software) usart will the transmitted data get corrupted due to extended soft ware delay(due to interrupts), which is used to generate the baud rate ?

Not if you intelligently use priority interrupts or alternativly give NOVOS a spin.

No priority interrupts, I am using pic16f877. I am talking about software usart and so it does not generate any interrupt ( for that matter i think even the hw uart lib of source boost does not generate interrupt, but does a software polling of the interrupt or status flags( the rx & tx interrupt enable bits are cleared). I don't want to use my own routine. If i use the SB lib i have the advantage of handling strings ,ascii etc with ease( i suppose, i haven't tried).

Use the hardware UART, problem solved. The problem with the SW UART is that any interrupts could stretch the bit time and so cause a mistransmissin/ reception. The hardware UART will handle the bit timing, and if your interrupt service is less than the time to TX/RX a byte via the UART you should have no problems. (assuming interrupts dont come flying in so fast that you cant read consecutive RX words).

Another solution is to generate a supervisor interrupt using a timer as the sole interrupt source at a rate sufficient to handle all situations, and poll all interrupts in the service.

The hardware USART really does not need or benifit from canned libraries, sorry but it is true. Aside from calculating the desired baudrate (usually the datasheet has a pre-calculated table anyway) and intializing the module (altho this is simple as well), every task you might do is simple to implement in a non-blocking method. Canned functions are usually blocking and polling to make it easier for people to use (they dont have to worry about setting up extra stuff).

Look at what you want to do, and then look at using the TXIF and RCIF interrupt flags. Careful usage and a wisely selected baudrate as Picxie suggests are your best solution.

Here is a very simple(and possibly flawed) off the cuff example of TX and RX interrupt usage. The rest of the code to handle the actual data at your leisure would be inside your main.


void interrupt(void)
{
   if(txif)    /* Transmit interrupt flag - triggers when empty */
   {
       txreg=_txArrayToSend[_txCount];    /* load buffer to send */
       if(_txCount == _txLength)    /* are we done yet? if so reset counter */
       {
           _txCount=0;
           _txDoneFlag = 1;    /* extra flag incase we want to send something else */
           txie = 0;    /* we are done so we can disable the interrupt */
       }
       else
       {
           _txCount++;    /* keep on counting */
       }
       txif = 0;
   }
 
   if(rcif)    /* rx interrupt */
   {
       _rxCapture[_rxCount] = rxreg;    /* capture values until we are done */
       _rxCount++;    /* array storage is easier to extract data from - redundancy, CRC. etc */
       rcif=0;
   }
}


Software UARTS implemented with cycle counting and interrupts are mutually exclusive. Using a RTOS does not solve the problem for such a SW UART implementation.

For most applications it is not necessary to implement a transmit interrupt handler. This is a task that can (usually) be handled as a polled function from a mainline task. This minimizes context switching and overhead especially when you consider that intercharacter latency variation for transmitted characters in a asynchronous environment is usually a non issue. A general exception to this guide would be in the event that each character received must also be echoed or repeated to another asynchronous port.

To minimize the interrupt overhead, ensure all variables within the handler are 8 bit variables. Clearing the RCIF flag is handled automatically when the rxreg is read. Clearing it manually (as shown above) can result in character loss in race conditions (don't do it). The PIC is brain dead with respect to its asynchronous port, in the event of an overrun error (not clearing the RXREG before the next character is received) the PIC disables the asynchronous receive logic - to avoid this problem the receive interrupt handler needs to check the error status and in event of error it needs to disable and immediately reenable the receive logic.

An alternative method of implementing a rx handler is to use a ring buffer with head and tail pointers. When a byte is received it is added to the buffer -rxCapture[head++]; if (head >= buffer_size) head = 0;

To determine if there is anything in the buffer then if (head != tail) // something is in the buffer ;

To extract a character from the buffer: new_char = rxCapture(tail++); if (tail >= buffer_size) tail = 0;

Clearing the RCIF flag is handled automatically when the rxreg is read. Clearing it manually (as shown above) can result in character loss in race conditions (don't do it). The PIC is brain dead with respect to its asynchronous port, in the event of an overrun error (not clearing the RXREG before the next character is received) the PIC disables the asynchronous receive logic - to avoid this problem the receive interrupt handler needs to check the error status and in event of error it needs to disable and immediately reenable the receive logic.

This is true, but also flawed in quite a lot of Microchip's silicon. There is a lot of errata stating that reading does not always clear the flag. As for the potential race condition, in practice i have yet to see it even when using baudrates in excess of 115.2k.

Depending on which family of devices your using the USART will disable after the second or third level buffers are full, but the interrupt flag will still be enabled.

Error checking is essential for any protocol, but is a bit advanced for someone trying to figure out the basics of using the USART.

I disagree. Lockup of the PIC's USART is a common trap for newbies - they waste a lot of time chasing phantom problems.

nn3turntable[edit]

http://forum.sourceboost.com/index.php?showtopic=3108&pid=11666&mode=threaded&start=#entry11666


We would like to announce the availability of Opensource BoostC Source code that may be of interest to SourceBoost Forum C programmers. This software source code is available for download now at:

http://sourceforge.net/projects/nn3turntable/

At the above location you can download the complete SourceBoost projects.

This embedded software system consists of two communicating applications written in SourceBoost Boost "C" for the PIC18 processor family on an I2C network. The software is the code basis for a model railroader to remotely operate auto-indexing turntables on model railroad layouts. The controller application allows a remote operator to operate a turntable several meters away by communicating with a turntable application. The turntable application accepts requests from a controller and precisely positions the turntable according to those requests. It also supplies status information for the controller to display to the operator. The controller application UI consists of status LEDs, push buttons, switches and a control knob. It communicates with a turntable via an I2C (small area) network interface. The turntable application's external apparatus consists of status LEDs, push buttons, a stepper motor, a home position detector and an I2C network interface. The turntable application supports very high precision positioning of a turntable by supporting micro-stepping of the stepper motor. It positions a turntable to any one of 7680 points on a circle. The turntable application allows operator programming of up to 80 feeder track locations. The turntable associates a knob position (on the controller) with a precise location. When the knob is turned (close) to the position, the turntable automatically steps to the memorized location. The software is organized into three groups. The common group consists of modules which contain highly reusable software for almost any interrupt driven small system. The following software modules are in the common group:

ADC - Hardware driver routines to perform analog to digital conversions user PIC16,PIC18 ADC module. CmdFormat - Routines to format messages for network transmission. CmdVerbs - Definitions of network messages sent between controller and turntable. EEprom - Hardware driver routines to efficiently write to eeproms. Button - Interrupt driven routines to manage any number of switches or buttons and debounce them and measure how long they are up (or down). LEDControl - Interrupt driven routines to manage any number of LEDs to vary their intensity and/or to operate patterns (for blinking and other effects). MsgQeueue - Routines to define and manage message queues to support asynchronous network transmission. RDC80 - Routine to operate a 360 degree knob using the ALPs RDC80 sensor. TTCrc8 - Routine to calculate CRC8 polynomials for error protection of messages. I2C - Interrupt driven hardware driver in C that supports slave, master and multi-master I2C bus communication. WalkRange - Routine to psuedo-randomly walk over the entire I2C address range upon Master collision. This optimally maximizes I2C network throughput while minimizing transmission delay. Turntable - Routines and definitions common to controlling a turntable.

While this software is coded in SourceBoost Boost"C" for the PIC16/PIC18 family of processors, it can also be fairly easily be ported and thus used for almost any small microcomputer. The turntable group (TTstepper) consists of many of the common modules and specific turntable modules:

TTstepper - Initialization and main loop for operating the turntable. aligntable - finds the turntable hardware home position. config - defines the hardware/software module configuration for turntable. indextable - manages the knob position to turntable location table kept in EEprom. motor - Interrupt drivern stepper motor driver; runs stepper motor control hardware in micro-stepping mode (allowing upto 7680 steps per revolution. StepperCmd - formats, sends and performs local or remote commands. StepperInterrupt - Manages all interrupts for hardware including all timers.


The controller group, TTcontrol, consists of many of the common modules and the following application specific modules.

TTcontrol - Initialization and main loop to remotely control turntable. config - defines TTcontrol hardware/software configuration. ControlCmds - formats and queues commands to be sent from local UI, also executes remote command requests/responses. ControlInterrupt - operates all interrupt drivers including timing drivers, I2C, LED, Button, ADC, EEprom. etc.


This software is written in "C" by Bruce Hunt(US) and Mark Langezaal(NL) over the past 9 months. The software is made available under the LGPL so that it can be used by anyone in the community needing (what we believe are high quality) "C" routines to operate small micro-computers. We wrote this software to support the hardware we designed to build low cost highly precise auto-indexing remotely controllable model railroad turntables applicable to many different scales including Zn3, Z, N, Nn3, H0, H0n3, S, Sn3, O, On3. The hardware is about to be made commercially available.

Our goals are to: make sure that people have access to the software that controls their hardware. to allow community improvements to the software (and hardware). to assure that improvements and updates are available at low cost. to promote the use of software controllers in realistic historical miniature modeling. The code is reasonably heavily documented to facilitate ease of re-use. In particular, the Common modules such as MsgQueue and I2C routines are heavily documented. The I2C module is particularly heavily documented (and tested). This is because of the pitfalls we found in implementing interrupt driven I2C code for the MSSP module in selected PIC 16 and 18 processors.

The Sourceboost IDE and the BoostC compiler have been invaluable tools to help us build this embedded application. We would like to thank Dave and Pavel for answering our questions and helping us understand how to best use the compiler and IDE -- but mostly for accelerating our ability to implement our ideas with excellent tools.

Mark Langezaal and Bruce Hunt


Its in SVN, download something like RapidSVN to get it.

http://nn3turntable.svn.sourceforge.net/viewvc/nn3turntable/

You can also browse it online too to see if it matches your needs:


may 27


http://forum.sourceboost.com/index.php?showtopic=3109&pid=11656&mode=threaded&start=#entry11656

I want to display a signed variable on a seven segment display. Right now i am checking if its a negative value if so converting it into positive value by multiplying it with -1 and then displaying it. Is this the only way to do it ? Consider using one of the standard conversion routines to converstion from a value into a series of digits including the sign: char* itoa( int val, char* buffer, unsigned char radix );



Dave, ascii values are rather cumbersome to use with seven seg. Just subtract 48 ( ascii code for '0' ) from each digit to convert to a decimal. The you will need to convert each value into the appropriate segments using some kind of lookup table.