0
\$\begingroup\$

I have a PIC18LF27J53 running properly and I'm able to make an LED blink. FOSC is at 8MHz (which is confirmed through the LED).

Now, I want to make the PIC send some bytes to the RaspberryPi via UART (I'm using minicom to inspect /dev/ttyAMA0 and have disabled both bluetooth and the serial console). I tried with both TX1 and remapped TX2 but I'm only receiving the same mess (fààþæ). I tried to invert the logic, but that didn't help and I'm receiving ~øxøxxøxþ instead.

This is my code to setup the UART interface (with BRGH, 8-bit BRG @ 9600):

TXSTA2   = 0b10100110;
RCSTA2   = 0b00010000;
BAUDCON2 = 0b01000010;
// BR=FOSC/(16(n+1)) <=> n=FOSC/BR/16-1
n = (uint8_t)round(1.0 * CLOCKSPEED / BAUDRATE / 16.0) - 1;
SPBRG2 = n;
RCSTA2bits.SPEN = 1;

The formula outputs 51 for CLOCKSPEED = 8MHz and BAUDRATE = 9600 which is the same as written in the datasheet (page 343).

This is the code I use to send a string:

void putc(char c)
{
    while(TXSTA2bits.TRMT == 0);
    TXREG2 = c;
}
void puts(const char *str)
{
    const char *p;
    for (p = str; *p; p++)
        putc(*p);
}

Finally, I call it like this:

const char *str = "HELLO\r\n";
puts(str);

What can I do to make the RaspberryPi receive the correct characters?

EDIT: I just tried to print the character U (01010101) continously via UART. Minicom receives continously alternating the chars f (01100110) and æ (11100110). So I'd guess that there is an issue with the baud rate. How can I check this and find the error?

\$\endgroup\$
  • \$\begingroup\$ Default INTOSC frequency is 4 MHz. Show us your CONFIG register settings and system clock initialization code. \$\endgroup\$ – Bruce Abbott Jan 23 '17 at 18:23
  • \$\begingroup\$ @BruceAbbott INTOSC is a 8MHz clock but it seems the derived FOSC is only 4MHz by default. I was using the default config of XC8, but setting PLLDIV to 2 and the IRCF bits to 7 it's now working without ugly workaround. \$\endgroup\$ – msrd0 Jan 23 '17 at 18:41
  • \$\begingroup\$ @BruceAbbott do you know whether the PLL will influence the value I have to use for CLOCKSPEED or will it always be calculated from INTOSC clock? \$\endgroup\$ – msrd0 Jan 23 '17 at 18:41
  • \$\begingroup\$ Examine the clock circuit on page 32 of the datasheet:- "FIGURE 3-1: PIC18F47J53 FAMILY CLOCK DIAGRAM". There are several different ways to set the system clock frequency. With OSCCON<1:0> = 00 (default value) the system clock comes from INTOSC postscaled by OSCCON<6:4>, and the PLL has no effect. \$\endgroup\$ – Bruce Abbott Jan 23 '17 at 19:02
0
\$\begingroup\$

I connected the TX pin of the PIC to a GPIO input pin of my RaspberryPi and wrote a little program to monitor what's going on:

    #include <assert.h>
    #include <fcntl.h>
    #include <stdint.h>
    #include <stdio.h>
    #include <sys/mman.h>
    #include <sys/stat.h>
    #include <sys/time.h>
    #include <time.h>
    #include <unistd.h>

    #define BLOCK_SIZE 256

    #define GPIO_IN(g)  *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
    #define GPIO_OUT(g) *(gpio+((g)/10)) |=  (1<<(((g)%10)*3))

    #define GPIO_SET(g)  *(gpio+7)  = 1<<(g)
    #define GPIO_CLR(g)  *(gpio+10) = 1<<(g)
    #define GPIO_LEV(g) (*(gpio+13) >> (g)) & 0x1

    #define PIN 18

    int                mem_fd;
    void              *gpio_map;
    volatile uint32_t *gpio;

    unsigned long ellapsed(struct timespec last, struct timespec now)
    {
      unsigned long diff = now.tv_sec - last.tv_sec;
      diff *= 1e9;
      diff += now.tv_nsec - last.tv_nsec;
      return diff;
    }

    int main()
    {
      mem_fd = open("/dev/gpiomem", O_RDWR|O_SYNC);
      assert(mem_fd != -1);

      gpio_map = mmap(NULL, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, mem_fd, 0);
      assert(gpio_map != MAP_FAILED);
      gpio = (volatile uint32_t*)gpio_map;

      GPIO_IN(PIN);

      struct timespec last, now;
      clock_gettime(CLOCK_BOOTTIME, &last);
      char state = 1;
      while (1)
        {
          if ((state & 0x1) != (GPIO_LEV(PIN)))
            {
              clock_gettime(CLOCK_BOOTTIME, &now);
              printf("state changed from %d to %d after %f µsecs (= %f kHz)\n", state, GPIO_LEV(PIN), ellapsed(last, now)/1000.0, 1.0/(ellapsed(last,now)/1e9)/1e3);
              last = now;
              state = GPIO_LEV(PIN);
            }
        }
    }

The speed was about 207 µsec per bit. I looked up the speed of uart and found that this equals a baud rate of 4800, exactly half of what I expected. Dividing n through 2 gives me the correct baud rate, although I don't understand why this is needed, as neither the datasheet nor the internet tells about such behaviour.

\$\endgroup\$
  • \$\begingroup\$ This isn't really an answer, it's just conforming that the baud rate is half what you expected. \$\endgroup\$ – Bruce Abbott Jan 23 '17 at 17:35
  • \$\begingroup\$ @BruceAbbott It is an ugly workaround but fixed my problem so I'd call it an answer. Still I don't know what causes the issue so if you know it please provide a better answer \$\endgroup\$ – msrd0 Jan 23 '17 at 17:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.