1

I am new to C programming and microcontrollers. I am using a PIC18F24K20 microcontroller with C18. I have it set up to receive information from a computer input using USART transmit and receive functions. My goal is to compare the received word against known words, and transmit something back to the computer based on what word was received. Below is the relevant code.

#include "p18f24k20.h"
#include "delays.h"
#include "string.h"
#include "stdlib.h"


void CommTransmit ( rom char * );

void main (void)
{
    char buf[11], data, T;
    int i;

    i = 0;
    memset(buf, 0, sizeof buf);

    while(1)
    {
        if (PIR1bits.RCIF)
        {
            data = USART_receive();
            if (data != 47)             // 47 is /, indicates end of string
            {
                buf[i] = data;
                i++;
            }
            else
            {
                // T = strcmppgm2ram(buf,(const far rom char*)"test");
                CommTransmit(buf);
                USART_transmit('t');
                buf[0] = 0'
            }
        }
    }
}


void CommTransmit ( rom char *CommVariable )
{
    char test;

    test = strcmppgm2ram(CommVariable, (const far rom char*)"test");
    if (test == 0)
    {
        USART_transmit('g');
    }
}

The code is currently set up to test to try to determine what is wrong. If I run it as is, the computer will receive a 't', as if the microcontroller ran through the CommTransmit function. However, it never transmits the 'g'. Even if I put a USART_transmit('g') call in the CommTransmit function, outside of and after the if statement, it never gets called (like it gets stuck in the strcmppgm2ram function?) but yet it still transmits the 't'.

It is also strange because if I put a break at the CommTransmit function and run through line by line, it seems to work properly. However, if I watch the CommVariable inside MPLAB IDE, it is never what it supposed to be (though the 'buf' variable prior to being called into the function is correct). From what I can tell, the value of CommVariable when I watch it depends on the size of the array.

From reading, I think it may caused by how the microcontroller stores the variable (program vs data memory?) but I'm not sure. Any help is greatly appreciated!

edit: I should also add that if I uncomment the T = strcmppgm2ram line in the else statement before the CommTransmit line, it works properly (T = 0 when the two strings are the same). I believe the array changes when I pass it through the function, which causes the strcmppgm2ram function to not work properly.

user3115691
  • 95
  • 4
  • 9
  • Hi. I haven't programmed on C18 (but have on other embedded systems); but I'm suspicious of `(const far rom char*)"test"`. If the string literal is not in the right area of memory then this cast won't move it, it'll just send a bogus pointer. What happens without the cast? – M.M Apr 10 '14 at 13:53
  • BTW check that `i < 11` in the `data != 47` case – M.M Apr 10 '14 at 13:54
  • 1
    Given the seemingly random behavior, it sounds like you have some memory-related bug somewhere. Some pointer or array bug corrupting memory, perhaps in strcmppgm2ram(). Is that a user-defined function or some library one? Also since this is a PIC, stack overflow is always a likely candidate. – Lundin Apr 10 '14 at 13:55
  • @lundin strcmppgm2ram() is a library function. Here is what the string.h file says about it: signed char strcmppgm2ram (auto const char *s1, auto const MEM_MODEL rom char *s2); /** name strcmpram2pgm * The {\bf strcmpram2pgm} function performs a {\bf strcmp} where {\bf s1} * points to program memory and {\bf s2} point to data memory. * param s1 pointer to string in program memory * param s2 pointer to string in data memory */ – user3115691 Apr 10 '14 at 14:35
  • @MattMcNabb: It appears to behave the same way without the casting. I got that line from [here](http://www.microchip.com/forums/m132084.aspx) – user3115691 Apr 10 '14 at 14:40
  • 1
    The parameter of the CommTransmit funtion is suspicious. Why is it `rom`? You are passing it a variable on the stack. (In general, I prefer to declare buffers outside of main to avoid using the stack at all.) – UncleO Apr 10 '14 at 16:36
  • @UncleO I had rom in to test. It seems to work the same with or without the rom parameter in CommTransmit (if I run through, it seems to ignore the CommTransmit function, but if I run it line by line it works properly). I also tried declaring buf outside of main and using it as a global variable in CommTransmit with the same results. – user3115691 Apr 10 '14 at 17:32
  • You'll simply have to debug the weird strcmppgm2ram function and see why it breaks your program... – Lundin Apr 11 '14 at 09:10
  • @Lundin I believe you are correct that it is a memory related bug. I changed the CommTransmit function to simply be: char test[11]; and strcmp(test,CommVariable) (I removed the roms). I have several other variables declared as char in my main function. I tested it by sending in "123456789" and I put a breakpoint in main directly after CommTransmit. What I found is that all of the variables I declare in main have been changed, in order, to 1-9 (so the first variable declared is 1, the 2nd is 2, and so on). Any ideas? – user3115691 Apr 15 '14 at 15:24
  • @user3115691 As already mentioned, you are using an ancient CPU architecture called PIC. Always suspect stack overflow at least 10 times per day. – Lundin Apr 16 '14 at 06:44

1 Answers1

1

Looking at signature for strcmppgm2ram

signed char strcmppgm2ram(const char * str1, const rom char * str2 );

I don't understand why do you have rom char * for CommVariable. From chapter 2.4.3 ram/rom Qualifiers of MPLAB® C18 C Compiler User’s Guide

Because the PICmicro microcontrollers use separate program memory and data memory address busses in their design, MPLAB C18 requires extensions to distinguish between data located in program memory and data located in data memory. /---/ Pointers can point to either data memory (ram pointers) or program memory (rom pointers). Pointers are assumed to be ram pointers unless declared as rom.

And in 2.7.3 String Constants:

An important consequence of the separate address spaces for MPLAB C18 is that pointers to data in program memory and pointers to data in data memory are not compatible. /---/ because they refer to different address spaces. /---/ MPLAB C18 automatically places all string constants in program memory. This type of a string constant is “array of char located in program memory”, (const rom char []).

And also it's not clear the purpose of type casting to const far rom char* for the second argument. That may cause stack corruption because far pointer has bigger size (24 bits). So, it looks like it should be rewritten as:

void CommTransmit (const char *CommVariable )
{
    if (!strcmppgm2ram(CommVariable, "test")) {
         USART_transmit('g');
    }
}
pmod
  • 10,450
  • 1
  • 37
  • 50