1 1
Peter Valencic

OrangepiPC H3 + Armbian + SPI step by step (C code)

Recommended Posts

Hi Martin and others :)

I started a new Thread because have problems using some third party interfaces with OrangePI running Armbian.

 

Well.. In my project I need to communicate with 5 sensors which have UART output so I decided to buy a circuit (uart2spi) which work well if connected to Arduino.

The Circuit description is available here: http://www.rowlandtechnology.com/projects/2015/09/25/spi-to-4-x-uart-bridge-multiuart-project/

 

First step:

This is how I have connected the circuit to GPIO bus on my OrangePi pc..

 

The circuit has (from left to right)

+3.3V pin, MISO, MOSI, SCK (clock), CS and GND..

I have connected those wires to GPIO pins:

+3.3V to pin 17

MOSI to pin 19

MISO to pin 21

SCK to pin 23

CS to pin 24  (chip select)

GND to pin 20

 

screenshot_2306.jpg

 

This is how it look like... (the green led on my interface is on so it's mean that power is on)

screenshot_2306.jpg

 

If I look at the tutorial on how to setup the board on Arduino is the same (you just connect wires) except CS is some output pin which you can togle on/off.. in my case I have connected those wire to orangepi on pin 24 (CE0)..

 

Now I would like to port Arduino library to C and here the problems begin...

 

first... the initialization of SPI...

In Arduino I have this kind of method  (SPIDivider is set to 250000 (250 kHz))

 

 

Arduino code:

void MULTIUART::initialise(int SPIDivider)
{
	SPI.begin();
    SPI.setBitOrder(MSBFIRST);
    SPI.setClockDivider(SPIDivider);
}

 

and here is my code in C but I don't know if this is  the right way to write over spi?

and also how to set-up bitOrderMask (if needed)? 

 

Orangepi code :


#include <iostream>
#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/times.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
#include <spi_lib.h>



using namespace std;

#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))

static const char *device = "/dev/spidev0.0";
static uint8_t mode = 3;
static uint8_t bits = 8;
static uint32_t speed = 250000;  //250kHz
static uint16_t delays;

static void pabort(const char *s) {
    perror(s);
    abort();
}


int main(int argc, char** argv) {
    int ret = 0;
    int fd;

    fd = open(device, O_RDWR);  //read write
    if (fd < 0) {
        printf("can't open device");
        return -1;
    }
    ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
    if (ret == -1) {
        printf("can't open device");
        return -1;
    }

    
    printf("spi mode: %d\n", mode);
    printf("bits per word: %d\n", bits);
    printf("max speed: %d Hz (%d KHz)\n", speed, speed / 1000);


    if (ioctl(fd, SPI_IOC_WR_MODE, &mode) == -1) pabort("Can't set SPI mode");

    
    
    close(fd);
    return ret;

}

from console i get:

screenshot_2306.jpg

 

now...

Here I have a function from Arduino to set BaudRate for specified channel on my interface.  (baud rate is selected with values from 0 to 7 (0=1200, 1=2400, 2=4800, 3=9600, 4=19200, 5=38400, 6=57600, 7=115200)

This function works well on Arduino (but.... if you see it uses digitalWrite command to pull down the signal on CS pin  and then the command is send over SPI.transfer function.. )

 

void MULTIUART::SetBaud(char UART, char BAUD)
{
	if (UART < 4)
	{
		if (BAUD < 10)
		{
			digitalWrite(_ss_pin, LOW);

			SPI.transfer(0x80 | UART);

			delayMicroseconds(50);

			SPI.transfer(BAUD);

			digitalWrite(_ss_pin, HIGH);

			delayMicroseconds(50);
		}
	}
}

 

Now I don't know if the same must be done on OrangePI with CS pin (pin 24 on GPIO or is this done by kernel)?  

I have ported this code above on orangepi like this:

 

void setBaudRate(int fd,char uart)
{
    if (uart <4)
    {
    int ret = -1;
    uint8_t tx_buffer_baud = (uint8_t)(0x80|uart); 
    
    //??? CS pin must be in LOW mode
                 
    ret = spi_write(fd,&tx_buffer_baud,1);
    printf("ret1: %d\n", ret);
    usleep(50);
    
    tx_buffer_baud = (uint8_t) 3;
    
    ret = spi_write(fd,&tx_buffer_baud,1);
    usleep(50);
    
    //??? CS pin must be in HIGH mode
    
    printf("ret1: %d\n", ret);
    }
}

 

So is the CS pin set to LOW before the command is send over SPI or it must be done manually? 

 

thank you for any info..

 

Share this post


Link to post
Share on other sites
22 minutes ago, Peter Valencic said:

So is the CS pin set to LOW before the command is send over SPI or it must be done manually? 

CS is handled by kernel, you shouldn't set it manually.

Share this post


Link to post
Share on other sites

ok.. I tryed with this code below...

#include <iostream>
#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/times.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
#include <spi_lib.h>



using namespace std;

#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))

static const char *device = "/dev/spidev0.0";
static uint8_t mode = 3;
static uint8_t bits = 8;
static uint32_t speed = 250000; //250kHz
static uint16_t delays;

static void pabort(const char *s) {
    perror(s);
    abort();
}

void setBaudRate(int fd, char uart) {
    if (uart < 4) {
        int ret = -1;
        uint8_t tx_buffer_baud = (uint8_t) (0x80 | uart); //9600 baud rate UART 1
        ret = spi_write(fd, &tx_buffer_baud, 1);
        printf("ret1: %d\n", ret);
        usleep(150);

        tx_buffer_baud = (uint8_t) 3;

        ret = spi_write(fd, &tx_buffer_baud, 1);
        usleep(150);
        printf("ret1: %d\n", ret);
    }
}

void TransmitString(int fd, char uart, char *DATA, char NUMBYTES) {
    char IDX = (0x0);
    int ret = -1;
    if (uart < 4) {
        uint8_t tx_buffer_baud = (uint8_t) (0x40 | uart); //9600 baud rate UART 1
        ret = spi_write(fd, &tx_buffer_baud, 1);
        usleep(150);

        tx_buffer_baud = (uint8_t) (NUMBYTES);
        ret = spi_write(fd, &tx_buffer_baud, 1);
        usleep(150);
        while (IDX < NUMBYTES) {
            tx_buffer_baud = (uint8_t) DATA[IDX];
            ret = spi_write(fd, &tx_buffer_baud, 1);
            usleep(150);
            IDX = IDX + 1;
        }
        usleep(150);
    }
}

int main(int argc, char** argv) {
    int ret = 0;
    int fd;

    fd = open(device, O_RDWR); //read write
    if (fd < 0) {
        printf("can't open device");
        return -1;
    }
    
    /*
	 * spi mode
	 */
	ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
	if (ret == -1)
		pabort("can't set spi mode");

	ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
	if (ret == -1)
		pabort("can't get spi mode");

	/*
	 * bits per word
	 */
	ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
	if (ret == -1)
		printf("can't set bits per word");

	ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
	if (ret == -1)
		printf("can't get bits per word");

	/*
	 * max speed hz
	 */
	ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
	if (ret == -1)
		printf("can't set max speed hz");

	ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
	if (ret == -1)
		printf("can't get max speed hz");


    
    printf("spi mode: %d\n", mode);
    printf("bits per word: %d\n", bits);
    printf("max speed: %d Hz (%d KHz)\n", speed, speed / 1000);


    

    //set baud rate 
    // Initialise the UART baud rates
    // 0=1200, 1=2400, 2=4800, 3=9600, 4=19200, 5=38400, 6=57600, 7=115200
    setBaudRate(fd, 0); //UART 1
   

    TransmitString(fd,0,"PETER",5);
   
    close(fd);
    return ret;

}

 

and connected the interface with USB/AURT cable...

On My PC RS232terminal I now receive some "garbage"...

 

screenshot_2311.jpg

Share this post


Link to post
Share on other sites

Glad to hear that and thanks for sharing. Often people tend to forget share their final solution ;)

Share this post


Link to post
Share on other sites
Guest
This topic is now closed to further replies.
1 1