Arduino Inter-Chip Serial Communication Wiki
Simple multi-station serial communications
Status: Beta
Brought to you by:
majenko
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; }