Menu

Raspberry Pi

Majenko Technologies

Adding RS-485 to a Raspberry Pi

You can directly connect a MAX3485 chip to the UART pins of the Raspberry Pi's GPIO connector.

With a little software magic you can also directly drive the RE# and DE lines of the MAX3485 chip with the right timing.

The trick is to monitor the UART's hardware registers to find out if the transmit FIFO is empty, and to check if the UART is actively transmitting or not.

// Access from ARM Running Linux

#define BCM2708_PERI_BASE        0x20000000
#define UART_BASE                (BCM2708_PERI_BASE + 0x201000)
#define GPIO_BASE                (BCM2708_PERI_BASE + 0x200000)

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <string.h>
#include <icsc.h>
#include <time.h>

#define PAGE_SIZE (4*1024)
#define BLOCK_SIZE (4*1024)

#define DR      (0x00 >> 2)
#define RSRECR  (0x04 >> 2)
#define FR      (0x18 >> 2)
#define ILPR    (0x20 >> 2)
#define IBRD    (0x24 >> 2)
#define FBRD    (0x28 >> 2)
#define LCRH    (0x2C >> 2)
#define CR      (0x30 >> 2)
#define IFLS    (0x34 >> 2)
#define IMSC    (0x38 >> 2)
#define RIS     (0x3C >> 2)
#define MIS     (0x40 >> 2)
#define ICR     (0x44 >> 2)
#define DMACR   (0x48 >> 2)
#define ITCR    (0x80 >> 2)
#define ITIP    (0x84 >> 2)
#define ITOP    (0x88 >> 2)
#define TDR     (0x8C >> 2)

#define FR_TXFE 0x80
#define FR_RXFF 0x40
#define FR_TXFF 0x20
#define FR_RXFE 0x10
#define FR_BUSY 0x08
#define FR_DCD  0x04
#define FR_DSR  0x02
#define FR_CTS  0x01

#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
#define OUT_GPIO(g) *(gpio+((g)/10)) |=  (1<<(((g)%10)*3))
#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))

#define GPIO_SET *(gpio+7)  // sets   bits which are 1 ignores bits which are 0
#define GPIO_CLR *(gpio+10) // clears bits which are 1 ignores bits which are 0

// I/O access
volatile unsigned *uart;
volatile unsigned *gpio;

// Map a block of peripheral registers into memory for easy access
volatile unsigned *map_peripheral(unsigned int address)
{
        void *map;
        int  mem_fd;
        volatile unsigned int *ptr;

        if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) {
                printf("can't open /dev/mem \n");
                exit(-1);
        }

        map = mmap(NULL, BLOCK_SIZE, PROT_READ|PROT_WRITE,
                MAP_SHARED, mem_fd, address);

        close(mem_fd);

        if (map == MAP_FAILED) {
                printf("mmap error %d\n", (int)map);//errno also set!
                exit(-1);
        }

        return (volatile unsigned *)map;
}

// This is the magic function for sending with synchronised GPIO
// signals.  First set the GPIO line high, then transmit the data.
// Following the transmit, monitor the TXFE flag (Transmit Fifo Empty).
// Once the FIFO is empty monitor the BUSY flag.  This will be true
// while the UART is transmitting the last character from the FIFO.
// Once it has all finished, lower the GPIO line again.
void rs485_send(unsigned char station, char command, unsigned char len, char *data)
{
        GPIO_SET = 1<<18;
        icsc_send(station, command, len, data);
        while ( !(uart[FR] & FR_TXFE)) {
                continue;
        }
        while ((uart[FR] & FR_BUSY)) {
                continue;
        }
        GPIO_CLR = 1<<18;
}

int main(int argc, char **argv)
{
        int g,rep;

        // Map the UART peripheral into memory
        uart = map_peripheral(UART_BASE);

        // Map the GPIO peripheral into memory
        gpio = map_peripheral(GPIO_BASE);

        // Configure the GPIO line and set it low
        INP_GPIO(18);
        OUT_GPIO(18);
        GPIO_CLR = 1<<18;

        // Set up the ICSC environment
        icsc_begin(4, B115200, "/dev/ttyAMA0");

        // Register any commands
//        icsc_register_command('p', &ping);

        // Keep running the process function to handle
        // incoming data.
        while (1) {
                icsc_process();
                usleep(10);
        }

        return 0;
}

Related

Wiki: RS-485

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.