On 06/01/2017 02:13 AM, Gene Heskett wrote:
> Hi Bertho; I haven't heard any more, so I am wondering if you've found 
> any more "magic beans"?

Yes, I think I've tracked down (most of) the problem(s). There are
several factors that play a role. Not all are solved or maybe solvable,
but the timing is much more stable, and very fast most of the time.


Problem 1:
The RPI3 has dynamic frequency scaling activated by default (ondemand
governor). This makes the Pi hop between 600MHz and 1.2GHz core
frequency. Very annoying and makes realtime rather unpredictable.

Add a line to /etc/rc.local:
  echo -n performance >
/sys/devices/system/cpu/cpufreq/policy0/scaling_governor

This will disable the frequency hopping on boot and lock the cores to
1.2GHz.


Problem 2:
The SPI peripheral input frequency appears to be hopping between 400MHz
and about 250MHz. This probably originates somewhere in the Linux kernel
as the kernel is in charge of clock-generation.

Changing the cpu's frequency scaling governor to "performance" makes the
clock more stable, hanging out at 400MHz most of the time, but I've seen
lower frequencies once in a while. The spidev driver actually reads the
(peripheral) clock frequency before a transfer starts and sets the
divider for each transfer. However, I have, at this moment, no clue how
to read the clock setting in userspace. This is a currently a minor
issue and should not give rise to major problems.


Problem 3:
The hm2_rpspi driver was miscalculating the clock-divider by statically
setting it to 8. This results in 50MHz SPI clock (400/8), which is what
we've been seeing. The 32MHz clock is the also explained by the
peripheral clock switching to ~250MHz.

The code is now changed to do the calculation correct and is
configurable with a module parameter "spiclk_rate" to set the clock (in
kHz) and defaults to 33000kHz.

It should be noted that the clock divider must be an even number,
resulting in frequencies of 200MHz, 100MHz, 66.6MHz, 50MHz, 40MHz,
33.3MHz, 28.5MHz, 25MHz, etc.. down to 6.1kHz.


Problem 4:
The hm2_rpspi driver was missing memory barriers in the peripheral
write/read operations. This resulted in inconsistencies. The code now
uses memory barrier instructions to ensure consistency.


I also unified the driver-code a bit and fixed some other problems I
could see. It should be functional. The SPI transfers are faster now
too. I've removed the inter-word delays by using the device's FIFO
properly. The chip-select latency is also minimal (factor 2..3 better
than spidev), but it can vary a bit if a (scheduling) interrupt delays
ending the transfer. The cookie-read is done in 5.7us versus 16.5us
using spidev.


Attached are the changed files. The .c and .h file are the modified
driver. These go in the source-tree at
"~/linuxcnc-git/src/hal/drivers/mesa-hostmot2/" (after copy do cd into
src and do make etc). The .hal and .ini files are the modified configs
for the sheldon lathe, adding the frequency configuration parameter, and
go in "~/linuxcnc/configs/sheldon-lathe/".

Try the changes if you will. I'm trying to build a new SD card with X
installed, but you should not stay awake for it to be finished (upload
alone of the compressed images takes already 3..4 hours).

-- 
Greetings Bertho

(disclaimers are disclaimed)
/*    This is a component for RaspberryPi to hostmot2 over SPI for linuxcnc.
 *    Copyright 2016 Matsche <tin...@play-pla.net>
 *    Copyright 2017 B.Stultiens <l...@vagrearg.org>
 *
 *    This program is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation; either version 2 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with this program; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

/* Without Source Tree */
#undef WOST

#include <ctype.h>
#include <fcntl.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/mman.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/fsuid.h>

#include "hal.h"
#include "rtapi.h"
#include "rtapi_app.h"

#include "rtapi_stdint.h"
#include "rtapi_bool.h"
#include "rtapi_gfp.h"

#include "rtapi_bool.h"

#if defined (WOST)
#include "include/hostmot2-lowlevel.h"
#include "include/hostmot2.h"
#else
#include "hostmot2-lowlevel.h"
#include "hostmot2.h"
#endif

#include "spi_common_rpspi.h"

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Matsche");
MODULE_DESCRIPTION("Driver for HostMot2 devices connected via SPI to RaspberryPi");
MODULE_SUPPORTED_DEVICE("Mesa-AnythingIO-7i90");

#define MAX_BOARDS	1		// FIXME: Cannot be other than 1; need CE_0/CE_1 distinctions for more boards
#define MAX_MSG		512

typedef struct hm2_rpspi_struct {
	hm2_lowlevel_io_t llio;		// Upstream container
	int nr;				// Board number
	uint32_t txBuf[MAX_MSG];	// Transmit buffer
	uint32_t rxBuf[MAX_MSG];	// Receive buffer
	uint32_t spiclkrate;		// SPI clock divider value
} hm2_rpspi_t;

typedef enum {
	RPI_UNSUPPORTED,
	RPI_1,		// Version 1
	RPI_2		// Version 2 and 3
} platform_t;

static uint32_t *peripheralmem = (uint32_t *)MAP_FAILED;	// mmap'ed peripheral memory
static size_t peripheralsize;					// Size of the mmap'ed block
static bcm2835_gpio_t *gpio;					// GPIO peripheral structure in mmap'ed address space
static bcm2835_spi_t *spi;					// SPI peripheral structure in mmap'ed address space
static platform_t platform;					// The RPI version

static char *config[MAX_BOARDS];
RTAPI_MP_ARRAY_STRING(config, MAX_BOARDS, "config string for the AnyIO boards (see hostmot2(9) manpage)")

/*
 * RPI3 NOTE:
 * The SPI frequency is wildly variable when the ondemand cpufreq governor is
 * active. This results is changing SPI frequencies depending on the system
 * load. You must set the performance governor for stable frequency. To set a
 * stable 1.2GHz core frequency, across all cores, put something like this in
 * /etc/rc.local:
 *   echo -n performance > /sys/devices/system/cpu/cpufreq/policy0/scaling_governor
 *
 * See also note in spi_xfer() below.
 */
#define F_PERI	400000000L
static int spiclk_rate = 33000;
RTAPI_MP_INT(spiclk_rate, "SPI clock rate in kHz (default 33000 kHz, slowest 6 kHz)")

static hm2_rpspi_t boards[MAX_BOARDS];	// FIXME: there can only be one board, need CE_0/CE_1 distinction
static int comp_id;

/*
 * Synchronized read and write to peripheral memory.
 * Ensures coherency between cores, cache and peripherals
 */
#define rmb()	__sync_synchronize()	// Read sync (finish all reads before continuing)
#define wmb()	__sync_synchronize()	// Write sync (finish all write before continuing)

static inline uint32_t reg_rd(const volatile void *addr)
{
	uint32_t val;
	val = *(volatile uint32_t *)addr;
	rmb();
	return val;
}

static inline void reg_wr(const volatile void *addr, uint32_t val)
{
	wmb();
	*(volatile uint32_t *)addr = val;
}

/*
 * Reset the SPI peripheral to inactive state and flushed
 */
static inline void spi_reset(void)
{
	uint32_t x = reg_rd(&spi->cs);
	x &= ~(SPI_CS_INTR | SPI_CS_INTD | SPI_CS_DMAEN | SPI_CS_TA);
	/* and reset RX/TX fifos */
	x |= SPI_CS_CLEAR_RX | SPI_CS_CLEAR_TX;
	reg_wr(&spi->cs, x);
	//reg_wr(&spi->dlen, 0);	// Not using DMA
}

/*************************************************/
// aib (address increment bit)
static inline uint32_t mk_read_cmd(uint16_t addr, unsigned msglen, bool aib)
{
	return 0 | (addr << 16) | 0xA000 | (aib ? 0x800 : 0) | (msglen << 4);
}

/*************************************************/
static inline uint32_t mk_write_cmd(uint16_t addr, unsigned msglen, bool aib)
{
	return 0 | (addr << 16) | 0xB000 | (aib ? 0x800 : 0) | (msglen << 4);
}

/*
 * Do a SPI transfer. Write the TX buffer and collect the return data into the
 * RX buffer.
 */
static void spi_xfer(hm2_rpspi_t *hm2, int size)
{
	uint32_t cs;
	uint32_t clkdiv;
	uint8_t *tbuff = (uint8_t *)hm2->txBuf;
	uint8_t *rbuff = (uint8_t *)hm2->rxBuf;
	int txlen = size;
	int rxlen = size;

	// Calculate the SPI clock divider
	//
	// FIXME: The SPI clock may vary and we have no idea what it currently
	// is. We assume a base-clock of 400MHz and derive the divider from
	// there. However, it seems that the peripheral clock flips between
	// 400MHz and 250MHz on the RPI3. We should get the periperal clock
	// setting before calculating the divider for SPI transfers. However,
	// how do we get the peripheral clock from userland?
	//
	// The current setup works just fine and we might not care too much. It
	// simply means that we sometimes are only at 62.5% of the speed we
	// actually want.
	clkdiv = F_PERI / hm2->spiclkrate;
	if(clkdiv > 65534)
		clkdiv = 0;		// Slowest possible
	else
		clkdiv += clkdiv & 1;	// Must be multiple of 2 (round to lower frequency)

	cs = reg_rd(&spi->cs);
	cs &= ~(SPI_CS_CS_10 | SPI_CS_CS_01 | SPI_CS_REN);	// Set CE_0 and disable 3-wire mode
	cs |= SPI_CS_TA;					// Activate transfer
	reg_wr(&spi->clk, clkdiv);				// Set clock divider
	reg_wr(&spi->cs, cs);					// Go!

	// Fill the TX fifo
	while(txlen && (reg_rd(&spi->cs) & SPI_CS_TXD)) {
		reg_wr(&spi->fifo, *tbuff++);
		--txlen;
	}

	// Read and write until all done
	while(rxlen) {
		cs = reg_rd(&spi->cs);
		if(cs & SPI_CS_RXD) {
			*rbuff++ = reg_rd(&spi->fifo);
			--rxlen;
		}
		if(txlen && (cs & SPI_CS_TXD)) {
			reg_wr(&spi->fifo, *tbuff++);
			--txlen;
		}
	}

	// Stop transfer
	spi_reset();
}

/*************************************************/
static int hm2_rpspi_write(hm2_lowlevel_io_t *llio, uint32_t addr, void *buffer, int size)
{
	hm2_rpspi_t *hm2 = (hm2_rpspi_t *)llio;

	if(size == 0)
		return 0;
	if((size % 4) || size / 4 >= MAX_MSG)
		return -EINVAL;

	hm2->txBuf[0] = mk_write_cmd(addr, size / 4, true);	// Setup write command
	memcpy(&hm2->txBuf[1], buffer, size);			// Fill tx buffer
	spi_xfer(hm2, size + 4);				// Perform transfer

	// We're done, there is no return data

	return 1;
}

/*************************************************/
static int hm2_rpspi_read(hm2_lowlevel_io_t *llio, uint32_t addr, void *buffer, int size)
{
	hm2_rpspi_t *hm2 = (hm2_rpspi_t *)llio;

	if(size == 0)
		return 0;
	if((size % 4) || size / 4 >= MAX_MSG)
		return -EINVAL;

	memset(hm2->txBuf, 0, sizeof(hm2->txBuf));		// We send 0 on reads
	hm2->txBuf[0] = mk_read_cmd(addr, size / 4, true);	// Setup read command
	spi_xfer(hm2, size + 4);				// Perform transfer

	// Copy the result
	memcpy(buffer, &hm2->rxBuf[1], size);

	return 1;
}

/*************************************************/
static int check_cookie(hm2_rpspi_t *board)
{
	const uint32_t xcookie[4] = {0x55aacafe, 0x54534f48, 0x32544f4d, 0x00000400};
	uint32_t cookie[4];
	int r = hm2_rpspi_read(&board->llio, 0x100, cookie, 16);
	if(r < 0)
		return r;

	if(memcmp(cookie, xcookie, sizeof(cookie))) {
		rtapi_print_msg(RTAPI_MSG_ERR, "hm2_rpspi: Invalid cookie, read: %08x %08x %08x %08x\n",
			cookie[0], cookie[1], cookie[2], cookie[3]);
		return -ENODEV;
	}
	return 0;
}

/*************************************************/
static int read_ident(hm2_rpspi_t *board, char *ident)
{
	return hm2_rpspi_read(&board->llio, 0x40c, ident, 8);
}

/*************************************************/
static int probe_board(hm2_rpspi_t *board) {
	int ret;
	char ident[9];
	char *base;

	if(spiclk_rate < 6 || spiclk_rate > 66000) {
		rtapi_print_msg(RTAPI_MSG_ERR, "hm2_rpspi: SPI clock rate '%d' too slow/fast. Must be >= 6 kHz and <= 66000 kHz\n", spiclk_rate);
		return -EINVAL;
	}

	board->spiclkrate = spiclk_rate * 1000;	// Command-line specifies in kHz

	if((ret = check_cookie(board) < 0))
		return ret;

	if((ret = read_ident(board, ident)) < 0)
		return ret;
	ident[8] = 0;

	if(!memcmp(ident, "MESA7I90", 8)) {
		base = "hm2_7i90";
		board->llio.num_ioport_connectors = 3;
		board->llio.pins_per_connector = 24;
		board->llio.ioport_connector_name[0] = "P1";
		board->llio.ioport_connector_name[1] = "P2";
		board->llio.ioport_connector_name[2] = "P3";
		board->llio.num_leds = 2;
		board->llio.fpga_part_number = "xc6slx9tq144";
	} else {
		int i;
		for(i = 0; i < sizeof(ident) - 1; i++) {
			if(!isprint(ident[i]))
				ident[i] = '?';
		}
		rtapi_print_msg(RTAPI_MSG_ERR, "hm2_rpspi: Unknown board: %.8s\n", ident);
		return -1;
	}

	rtapi_print_msg(RTAPI_MSG_ERR, "hm2_rpspi: Base: %s.%d", base, board->nr);
	rtapi_snprintf(board->llio.name, sizeof(board->llio.name), "%s.%d", base, board->nr);
	board->llio.comp_id = comp_id;
	board->llio.private = &board;
	board->llio.read = hm2_rpspi_read;
	board->llio.write = hm2_rpspi_write;
	board->llio.queue_read = 0;
	board->llio.queue_write = 0;

	return 0;
}

/*************************************************/
static int map_gpio(void)
{
	int fd;
	uint32_t membase = BCM2835_GPIO_BASE;	// We know that the GPIO peripheral is first in the map
	long pagesize = sysconf(_SC_PAGESIZE);	// Default mapped page size multiple

	// error, zero or not power of two
	if(-1 == pagesize || !pagesize || (pagesize & (pagesize-1))) {
		rtapi_print_msg(RTAPI_MSG_ERR, "hm2_rpspi: Pagesize is bad (%ld), assuming 4kByte\n", pagesize);
		pagesize = 4096;	// We assume this is a 12-bit (4k) page system, pretty safe
	}

	// Size is independent of the Pi we are running on
	peripheralsize = BCM2835_SPI_END - membase;	// We know that the SPI peripheral is last in the map
	peripheralsize = (peripheralsize + (uint32_t)(pagesize - 1)) & (uint32_t)~pagesize;	// Round up to next full page

	switch (platform) {
	case RPI_1:
		break;
	case RPI_2:	// for RPI 3 too
		membase += BCM2709_OFFSET;
		break;
	default:
		rtapi_print_msg(RTAPI_MSG_ERR, "hm2_rpspi: Plattform not supported\n");
		return -1;
	}

	if((fd = rtapi_open_as_root("/dev/mem", O_RDWR | O_SYNC)) < 0) {
		rtapi_print_msg(RTAPI_MSG_ERR, "hm2_rpspi: can't open /dev/mem\n");
		return -1;
	}

	/* mmap BCM2835 GPIO and SPI peripherals */
	peripheralmem = mmap(NULL, peripheralsize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, membase);
	close(fd);

	if(peripheralmem == MAP_FAILED) {
		rtapi_print_msg(RTAPI_MSG_ERR, "hm2_rpspi: Can't map peripherals\n");
		return -2;
	}

	gpio = (bcm2835_gpio_t *)peripheralmem;
	spi  = (bcm2835_spi_t *)(peripheralmem + (BCM2835_SPI_OFFSET - BCM2835_GPIO_OFFSET) / sizeof(*peripheralmem));

	rtapi_print_msg(RTAPI_MSG_INFO, "hm2_rpspi: Mapped peripherals from 0x%08x (size 0x%08x) to gpio:0x%p, spi:0x%p\n", membase, peripheralsize, gpio, spi);

	return 0;
}

/*************************************************/
static void waste_150_cycles(void)
{
	uint32_t x __attribute__((unused));
	unsigned i;
	// A read, an increment, a test and a jump. Should be at least 150 cycles
	for(i = 0; i < 50; i++)
		x = reg_rd(&gpio->gplev0);	// Just read the pin register, nothing interesting to do here
}

/*************************************************/
static inline void bcm2835_gpio_fsel(bcm2835_gpio_t *pio, uint32_t pin, uint32_t func)
{
	if(pin <= 53) {	/* There are 54 GPIOs */
		uint32_t bits = pin * 3;	/* Three bits per fsel field and 10 gpio per uint32_t */
		reg_wr(&pio->gpfsel[bits / 30], (reg_rd(&pio->gpfsel[bits / 30]) & ~(7 << (bits % 30))) | ((func & 7) << (bits % 30)));
	}
}

/*************************************************/
static void setup_gpio(void)
{
	// Setup SPI pins to SPI
	bcm2835_gpio_fsel(gpio,  8, GPIO_FSEL_8_SPI0_CE0_N);
	bcm2835_gpio_fsel(gpio,  9, GPIO_FSEL_9_SPI0_MISO);
	bcm2835_gpio_fsel(gpio, 10, GPIO_FSEL_10_SPI0_MOSI);
	bcm2835_gpio_fsel(gpio, 11, GPIO_FSEL_11_SPI0_SCLK);

	// Disable pullups on the pins so they are not interfering in impedance
	reg_wr(&gpio->gppudclk0, 0);	// We are not sure about the previous state, make sure
	reg_wr(&gpio->gppudclk1, 0);
	waste_150_cycles();		// See GPPUDCLKn description
	reg_wr(&gpio->gppud, GPIO_GPPUD_OFF);
	waste_150_cycles();
	reg_wr(&gpio->gppudclk0, (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11));
	reg_wr(&gpio->gppudclk1, 0);
	waste_150_cycles();
	reg_wr(&gpio->gppudclk0, 0);
	reg_wr(&gpio->gppudclk1, 0);

	spi_reset();
}

/*************************************************/
static void restore_gpio(void)
{
	// Restore all SPI pins to inputs and enable pull-up (no dangling inputs)
	reg_wr(&gpio->gppudclk0, 0);	// We do not know the previous state, make sure
	reg_wr(&gpio->gppudclk1, 0);
	waste_150_cycles();		// See GPPUDCLKn description

	// Enable pullups on pins so they are not floating inputs
	reg_wr(&gpio->gppud, GPIO_GPPUD_PULLUP);
	waste_150_cycles();
	reg_wr(&gpio->gppudclk0, (1 << 8) | (1 << 9) | (1 << 10) | (1 << 11));
	reg_wr(&gpio->gppudclk1, 0);
	waste_150_cycles();
	reg_wr(&gpio->gppud, GPIO_GPPUD_OFF);
	reg_wr(&gpio->gppudclk0, 0);
	reg_wr(&gpio->gppudclk1, 0);

	// Set SPI pins to GPIO input
	bcm2835_gpio_fsel(gpio,  8, GPIO_FSEL_X_GPIO_INPUT);
	bcm2835_gpio_fsel(gpio,  9, GPIO_FSEL_X_GPIO_INPUT);
	bcm2835_gpio_fsel(gpio, 10, GPIO_FSEL_X_GPIO_INPUT);
	bcm2835_gpio_fsel(gpio, 11, GPIO_FSEL_X_GPIO_INPUT);
}

/*************************************************/
#define CPUINFO_BUFSIZE	(16*1024)	// Should be large enough for now
static platform_t check_platform(void)
{
	FILE *fp;
	char *buf;
	size_t fsize;
	platform_t rv = RPI_UNSUPPORTED;

	if(!(buf = malloc(CPUINFO_BUFSIZE))) {
		rtapi_print_msg(RTAPI_MSG_ERR, "hm2_rpspi: No dynamic memory\n");
		return RPI_UNSUPPORTED;
	}
	if(!(fp = fopen("/proc/cpuinfo", "r"))) {
		rtapi_print_msg(RTAPI_MSG_ERR, "hm2_rpspi: Failed to open /proc/cpuinfo\n");
		goto check_exit;
	}
	fsize = fread(buf, 1, CPUINFO_BUFSIZE - 1, fp);
	fclose(fp);

	// we have truncated cpuinfo return unsupported
	if(!fsize || fsize == sizeof(buf) - 1) {
		rtapi_print_msg(RTAPI_MSG_ERR, "hm2_rpspi: Platform detection memory buffer too small\n");
		goto check_exit;
	}

	/* NUL terminate the buffer */
	buf[fsize] = '\0';

	if(strstr(buf, "BCM2708")) {
		rv = RPI_1;
	} else if(strstr(buf, "BCM2709")) {
		rv = RPI_2;	//for RPI 3 too
	} else if(strstr(buf, "BCM2835")) {	// starting with 4.8 kernels revision tag has board details
		char *rev_val = strstr(buf, "Revision");
		if(rev_val) {
			char *rev_start = strstr(rev_val, ": ");
			unsigned long rev = strtol(rev_start + 2, NULL, 16);

			if(rev <= 0xffff)
				rv = RPI_1; // pre pi2 revision scheme
			else {
				switch((rev & 0xf000) >> 12) {
				case 0: //bcm2835
					rv = RPI_1;
					break;
				case 1: //bcm2836
				case 2: //bcm2837
					rv = RPI_2;	// peripheral base is same on pi2/3
					break;
				default:
					break;
				}
			}
		}
	}

check_exit:
	free(buf);
	return rv;
}

/*************************************************/
static int hm2_rpspi_setup(void)
{
	int i, retval = -1;

	platform = check_platform();

	if(platform == RPI_UNSUPPORTED) {
		rtapi_print_msg(RTAPI_MSG_ERR, "hm2_rpspi: Unsupported Platform, only Raspberry1/2/3 supported.\n");
		return retval;
	}

	if((retval = map_gpio()) < 0) {
		rtapi_print_msg(RTAPI_MSG_ERR, "hm2_rpspi: cannot map GPIO memory.\n");
		return retval;
	}

	setup_gpio();

	for(i=0; i<MAX_BOARDS; i++) {
		boards[i].nr = i;
		if((retval = probe_board(&boards[i])) < 0)
			return retval;
		if((retval = hm2_register(&boards[i].llio, config[i])) < 0) {
			rtapi_print_msg(RTAPI_MSG_ERR, "hm2_rpspi: hm2_register() failed.\n");
			return retval;
		}
	}

	return 0;
}

/*************************************************/
static void hm2_rpspi_cleanup(void)
{
	if((void *)peripheralmem != MAP_FAILED) {
		restore_gpio();
		munmap(peripheralmem, peripheralsize);
	}
}

/*************************************************/
int rtapi_app_main()
{
	int ret;

	if((comp_id = ret = hal_init("hm2_rpspi")) < 0)
		goto fail;

	if((ret = hm2_rpspi_setup()) < 0)
		goto fail;

	hal_ready(comp_id);
	return 0;

fail:
	hm2_rpspi_cleanup();
	return ret;
}

/*************************************************/
void rtapi_app_exit(void)
{
	hm2_rpspi_cleanup();
	hal_exit(comp_id);
}
/*   This is a component  for RaspberryPi to FPGA over SPI for linuxcnc.
 *    Copyright 2013 Matsche <tin...@play-pla.net>
 *                               based on GP Orcullo's picnc driver and
 *				 based on the pluto_common.h from Jeff Epler <jep...@unpythonic.net>
 *    Copyright 2017 B.Stultiens <l...@vagrearg.org>
 *
 *
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

#ifndef HAL_RPSPI_H
#define HAL_RPSPI_H

/*
 * Broadcom defines
 *
 * Peripheral description see:
 * - https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2835/BCM2835-ARM-Peripherals.pdf
 * - http://elinux.org/RPi_BCM2835_GPIOs
 * - http://elinux.org/BCM2835_datasheet_errata
 */

#define BCM2835_PERI_BASE	0x20000000
#define BCM2835_GPIO_OFFSET	0x200000
#define BCM2835_SPI_OFFSET	0x204000

#define BCM2835_GPIO_BASE	(BCM2835_PERI_BASE + BCM2835_GPIO_OFFSET)	/* GPIO controller */
#define BCM2835_SPI_BASE	(BCM2835_PERI_BASE + BCM2835_SPI_OFFSET)	/* SPI controller */
#define BCM2835_GPIO_END	(BCM2835_GPIO_BASE + sizeof(bcm2835_gpio_t))
#define BCM2835_SPI_END		(BCM2835_SPI_BASE + sizeof(bcm2835_spi_t))

#define BCM2709_OFFSET		0x1F000000

#if !defined(__I) && !defined(__O) && !defined(__IO)
#ifdef __cplusplus
#define __I	volatile	/* read only permission */
#else
#define __I	volatile const	/* read only permission */
#endif
#define __O	volatile	/* write only permission */
#define __IO	volatile	/* read/write permission */
#else
#error "Possible define collision for __I, __O and __IO"
#endif

/*
 * Alternate function specification see
 */
#define GPIO_FSEL_X_GPIO_INPUT		0	/* All pin's function 0 is input */
#define GPIO_FSEL_X_GPIO_OUTPUT		1	/* All pin's function 1 is output */

#define GPIO_FSEL_0_SDA0		4
#define GPIO_FSEL_0_SA5			5
#define GPIO_FSEL_0_PCLK		6
#define GPIO_FSEL_0_SDA0		4
#define GPIO_FSEL_0_SA5			5
#define GPIO_FSEL_0_PCLK		6
#define GPIO_FSEL_1_SCL0		4
#define GPIO_FSEL_1_SA4			5
#define GPIO_FSEL_1_DE			6
#define GPIO_FSEL_2_SDA1		4
#define GPIO_FSEL_2_SA3			5
#define GPIO_FSEL_2_LCD_VSYNC		6
#define GPIO_FSEL_3_SCL1		4
#define GPIO_FSEL_3_SA2			5
#define GPIO_FSEL_3_LCD_HSYNC		6
#define GPIO_FSEL_4_GPCLK0		4
#define GPIO_FSEL_4_SA1			5
#define GPIO_FSEL_4_DPI_D0		6
#define GPIO_FSEL_4_ARM_TDI		2
#define GPIO_FSEL_5_GPCLK1		4
#define GPIO_FSEL_5_SA0			5
#define GPIO_FSEL_5_DPI_D1		6
#define GPIO_FSEL_5_ARM_TDO		2
#define GPIO_FSEL_6_GPCLK2		4
#define GPIO_FSEL_6_SOE_N		5
#define GPIO_FSEL_6_SE			5
#define GPIO_FSEL_6_DPI_D2		6
#define GPIO_FSEL_6_ARM_RTCK		2
#define GPIO_FSEL_7_SPI0_CE1_N		4
#define GPIO_FSEL_7_SWE_N		5
#define GPIO_FSEL_7_SRW_N		5
#define GPIO_FSEL_7_DPI_D3		6
#define GPIO_FSEL_8_SPI0_CE0_N		4
#define GPIO_FSEL_8_SD0			5
#define GPIO_FSEL_8_DPI_D4		6
#define GPIO_FSEL_9_SPI0_MISO		4
#define GPIO_FSEL_9_SD1			5
#define GPIO_FSEL_9_DPI_D5		6
#define GPIO_FSEL_10_SPI0_MOSI		4
#define GPIO_FSEL_10_SD2		5
#define GPIO_FSEL_10_DPI_D6		6
#define GPIO_FSEL_11_SPI0_SCLK		4
#define GPIO_FSEL_11_SD3		5
#define GPIO_FSEL_11_DPI_D7		6
#define GPIO_FSEL_12_PWM0		4
#define GPIO_FSEL_12_SD4		5
#define GPIO_FSEL_12_DPI_D8		6
#define GPIO_FSEL_12_ARM_TMS		2
#define GPIO_FSEL_13_PWM1		4
#define GPIO_FSEL_13_SD5		5
#define GPIO_FSEL_13_DPI_D9		6
#define GPIO_FSEL_13_ARM_TCK		2
#define GPIO_FSEL_14_TXD0		4
#define GPIO_FSEL_14_SD6		5
#define GPIO_FSEL_14_DPI_D10		6
#define GPIO_FSEL_14_TXD1		2
#define GPIO_FSEL_15_RXD0		4
#define GPIO_FSEL_15_SD7		5
#define GPIO_FSEL_15_DPI_D11		6
#define GPIO_FSEL_15_RXD1		2
#define GPIO_FSEL_16_FL0		4
#define GPIO_FSEL_16_SD8		5
#define GPIO_FSEL_16_DPI_D12		6
#define GPIO_FSEL_16_CTS0		7
#define GPIO_FSEL_16_SPI1_CE2_N		3
#define GPIO_FSEL_16_CTS1		2
#define GPIO_FSEL_17_FL1		4
#define GPIO_FSEL_17_SD9		5
#define GPIO_FSEL_17_DPI_D13		6
#define GPIO_FSEL_17_RTS0		7
#define GPIO_FSEL_17_SPI1_CE1_N		3
#define GPIO_FSEL_17_RTS1		2
#define GPIO_FSEL_18_PCM_CLK		4
#define GPIO_FSEL_18_SD10		5
#define GPIO_FSEL_18_DPI_D14		6
#define GPIO_FSEL_18_BSCSLSDA		7
#define GPIO_FSEL_18_MOSI		7
#define GPIO_FSEL_18_SPI1_CE0_N		3
#define GPIO_FSEL_18_PWM0		2
#define GPIO_FSEL_19_PCM_FS		4
#define GPIO_FSEL_19_SD11		5
#define GPIO_FSEL_19_DPI_D15		6
#define GPIO_FSEL_19_BSCSLSCL		7
#define GPIO_FSEL_19_SCLK		7
#define GPIO_FSEL_19_SPI1_MISO		3
#define GPIO_FSEL_19_PWM1		2
#define GPIO_FSEL_20_PCM_DIN		4
#define GPIO_FSEL_20_SD12		5
#define GPIO_FSEL_20_DPI_D16		6
#define GPIO_FSEL_20_BSCSL		7
#define GPIO_FSEL_20_MISO		7
#define GPIO_FSEL_20_SPI1_MOSI		3
#define GPIO_FSEL_20_GPCLK0		2
#define GPIO_FSEL_21_PCM_DOUT		4
#define GPIO_FSEL_21_SD13		5
#define GPIO_FSEL_21_DPI_D17		6
#define GPIO_FSEL_21_BSCSL		7
#define GPIO_FSEL_21_CE_N		7
#define GPIO_FSEL_21_SPI1_SCLK		3
#define GPIO_FSEL_21_GPCLK1		2
#define GPIO_FSEL_22_SD0_CLK		4
#define GPIO_FSEL_22_SD14		5
#define GPIO_FSEL_22_DPI_D18		6
#define GPIO_FSEL_22_SD1_CLK		7
#define GPIO_FSEL_22_ARM_TRST		3
#define GPIO_FSEL_23_SD0_CMD		4
#define GPIO_FSEL_23_SD15		5
#define GPIO_FSEL_23_DPI_D19		6
#define GPIO_FSEL_23_SD1_CMD		7
#define GPIO_FSEL_23_ARM_RTCK		3
#define GPIO_FSEL_24_SD0_DAT0		4
#define GPIO_FSEL_24_SD16		5
#define GPIO_FSEL_24_DPI_D20		6
#define GPIO_FSEL_24_SD1_DAT0		7
#define GPIO_FSEL_24_ARM_TDO		3
#define GPIO_FSEL_25_SD0_DAT1		4
#define GPIO_FSEL_25_SD17		5
#define GPIO_FSEL_25_DPI_D21		6
#define GPIO_FSEL_25_SD1_DAT1		7
#define GPIO_FSEL_25_ARM_TCK		3
#define GPIO_FSEL_26_SD0_DAT2		4
#define GPIO_FSEL_26_TE0		5
#define GPIO_FSEL_26_DPI_D22		6
#define GPIO_FSEL_26_SD1_DAT2		7
#define GPIO_FSEL_26_ARM_TDI		3
#define GPIO_FSEL_27_SD0_DAT3		4
#define GPIO_FSEL_27_TE1		5
#define GPIO_FSEL_27_DPI_D23		6
#define GPIO_FSEL_27_SD1_DAT3		7
#define GPIO_FSEL_27_ARM_TMS		3
#define GPIO_FSEL_28_SDA0		4
#define GPIO_FSEL_28_SA5		5
#define GPIO_FSEL_28_PCM_CLK		6
#define GPIO_FSEL_28_FL0		7
#define GPIO_FSEL_29_SCL0		4
#define GPIO_FSEL_29_SA4		5
#define GPIO_FSEL_29_PCM_FS		6
#define GPIO_FSEL_29_FL1		7
#define GPIO_FSEL_30_TE0		4
#define GPIO_FSEL_30_SA3		5
#define GPIO_FSEL_30_PCM_DIN		6
#define GPIO_FSEL_30_CTS0		7
#define GPIO_FSEL_30_CTS1		2
#define GPIO_FSEL_31_FL0		4
#define GPIO_FSEL_31_SA2		5
#define GPIO_FSEL_31_PCM_DOUT		6
#define GPIO_FSEL_31_RTS0		7
#define GPIO_FSEL_31_RTS1		2
#define GPIO_FSEL_32_GPCLK0		4
#define GPIO_FSEL_32_SA1		5
#define GPIO_FSEL_32_RING_OCLK		6
#define GPIO_FSEL_32_TXD0		7
#define GPIO_FSEL_32_TXD1		2
#define GPIO_FSEL_33_FL1		4
#define GPIO_FSEL_33_SA0		5
#define GPIO_FSEL_33_TE1		6
#define GPIO_FSEL_33_RXD0		7
#define GPIO_FSEL_33_RXD1		2
#define GPIO_FSEL_34_GPCLK0		4
#define GPIO_FSEL_34_SOE_N		5
#define GPIO_FSEL_34_SE			5
#define GPIO_FSEL_34_TE2		6
#define GPIO_FSEL_34_SD1_CLK		7
#define GPIO_FSEL_35_SPI0_CE1_N		4
#define GPIO_FSEL_35_SWE_N		5
#define GPIO_FSEL_35_SRW_N		5
#define GPIO_FSEL_35_SD1_CMD		7
#define GPIO_FSEL_36_SPI0_CE0_N		4
#define GPIO_FSEL_36_SD0		5
#define GPIO_FSEL_36_TXD0		6
#define GPIO_FSEL_36_SD1_DAT0		7
#define GPIO_FSEL_37_SPI0_MISO		4
#define GPIO_FSEL_37_SD1		5
#define GPIO_FSEL_37_RXD0		6
#define GPIO_FSEL_37_SD1_DAT1		7
#define GPIO_FSEL_38_SPI0_MOSI		4
#define GPIO_FSEL_38_SD2		5
#define GPIO_FSEL_38_RTS0		6
#define GPIO_FSEL_38_SD1_DAT2		7
#define GPIO_FSEL_39_SPI0_SCLK		4
#define GPIO_FSEL_39_SD3		5
#define GPIO_FSEL_39_CTS0		6
#define GPIO_FSEL_39_SD1_DAT3		7
#define GPIO_FSEL_40_PWM0		4
#define GPIO_FSEL_40_SD4		5
#define GPIO_FSEL_40_SD1_DAT4		7
#define GPIO_FSEL_40_SPI2_MISO		3
#define GPIO_FSEL_40_TXD1		2
#define GPIO_FSEL_41_PWM1		4
#define GPIO_FSEL_41_SD5		5
#define GPIO_FSEL_41_TE0		6
#define GPIO_FSEL_41_SD1_DAT5		7
#define GPIO_FSEL_41_SPI2_MOSI		3
#define GPIO_FSEL_41_RXD1		2
#define GPIO_FSEL_42_GPCLK1		4
#define GPIO_FSEL_42_SD6		5
#define GPIO_FSEL_42_TE1		6
#define GPIO_FSEL_42_SD1_DAT6		7
#define GPIO_FSEL_42_SPI2_SCLK		3
#define GPIO_FSEL_42_RTS1		2
#define GPIO_FSEL_43_GPCLK2		4
#define GPIO_FSEL_43_SD7		5
#define GPIO_FSEL_43_TE2		6
#define GPIO_FSEL_43_SD1_DAT7		7
#define GPIO_FSEL_43_SPI2_CE0_N		3
#define GPIO_FSEL_43_CTS1		2
#define GPIO_FSEL_44_GPCLK1		4
#define GPIO_FSEL_44_SDA0		5
#define GPIO_FSEL_44_SDA1		6
#define GPIO_FSEL_44_TE0		7
#define GPIO_FSEL_44_SPI2_CE1_N		3
#define GPIO_FSEL_45_PWM1		4
#define GPIO_FSEL_45_SCL0		5
#define GPIO_FSEL_45_SCL1		6
#define GPIO_FSEL_45_TE1		7
#define GPIO_FSEL_45_SPI2_CE2_N		3
/*
 * GPIO 46..53 are on port 2, but only available on the compute module. Anyway,
 * these are SD-card interface lines and better not meddled with.
 */

#define GPIO_GPPUD_OFF		0
#define GPIO_GPPUD_PULLDOWN	1
#define GPIO_GPPUD_PULLUP	2

/* BCM2835 GPIO peripheral register map specification */
typedef struct __bcm2835_gpio_t {
	union {
		struct {
			__IO	uint32_t	gpfsel0;	/* 0x000 GPIO Function Select 0 */
			__IO	uint32_t	gpfsel1;	/* 0x004 GPIO Function Select 1 */
			__IO	uint32_t	gpfsel2;	/* 0x008 GPIO Function Select 2 */
			__IO	uint32_t	gpfsel3;	/* 0x00c GPIO Function Select 3 */
			__IO	uint32_t	gpfsel4;	/* 0x010 GPIO Function Select 4 */
			__IO	uint32_t	gpfsel5;	/* 0x014 GPIO Function Select 5 */
		};
		__IO	uint32_t	gpfsel[6];
	};
	__I	uint32_t	reserved018;
	union {
		struct {
			__O	uint32_t	gpset0;		/* 0x01c GPIO Pin Output Set 0 */
			__O	uint32_t	gpset1;		/* 0x020 GPIO Pin Output Set 1 */
		};
		__O	uint32_t	gpset[2];
	};
	__I	uint32_t	reserved024;
	union {
		struct {
			__O	uint32_t	gpclr0;		/* 0x028 GPIO Pin Output Clear 0 */
			__O	uint32_t	gpclr1;		/* 0x02c GPIO Pin Output Clear 1 */
		};
		__O	uint32_t	gpclr[2];
	};
	__I	uint32_t	reserved030;
	__I	uint32_t	gplev0;		/* 0x034 GPIO Pin Level 0 */
	__I	uint32_t	gplev1;		/* 0x038 GPIO Pin Level 1 */
	__I	uint32_t	reserved03c;
	__IO	uint32_t	gpeds0;		/* 0x040 GPIO Pin Event Detect Status 0 */
	__IO	uint32_t	gpeds1;		/* 0x044 GPIO Pin Event Detect Status 1 */
	__I	uint32_t	reserved048;
	__IO	uint32_t	gpren0;		/* 0x04c GPIO Pin Rising Edge Detect Enable 0 */
	__IO	uint32_t	gpren1;		/* 0x050 GPIO Pin Rising Edge Detect Enable 1 */
	__I	uint32_t	reserved054;
	__IO	uint32_t	gpfen0;		/* 0x058 GPIO Pin Falling Edge Detect Enable 0 */
	__IO	uint32_t	gpfen1;		/* 0x05c GPIO Pin Falling Edge Detect Enable 1 */
	__I	uint32_t	reserved060;
	__IO	uint32_t	gphen0;		/* 0x064 GPIO Pin High Detect Enable 0 */
	__IO	uint32_t	gphen1;		/* 0x068 GPIO Pin High Detect Enable 1 */
	__I	uint32_t	reserved06c;
	__IO	uint32_t	gplen0;		/* 0x070 GPIO Pin Low Detect Enable 0 */
	__IO	uint32_t	gplen1;		/* 0x074 GPIO Pin Low Detect Enable 1 */
	__I	uint32_t	reserved078;
	__IO	uint32_t	gparen0;	/* 0x07c GPIO Pin Async. Rising Edge Detect 0 */
	__IO	uint32_t	gparen1;	/* 0x080 GPIO Pin Async. Rising Edge Detect 1 */
	__I	uint32_t	reserved084;
	__IO	uint32_t	gpafen0;	/* 0x088 GPIO Pin Async. Falling Edge Detect 0 */
	__IO	uint32_t	gpafen1;	/* 0x08c GPIO Pin Async. Falling Edge Detect 1 */
	__I	uint32_t	reserved090;
	__IO	uint32_t	gppud;		/* 0x094 GPIO Pin Pull-up/down Enable */
	__IO	uint32_t	gppudclk0;	/* 0x098 GPIO Pin Pull-up/down Enable Clock 0 */
	__IO	uint32_t	gppudclk1;	/* 0x09c GPIO Pin Pull-up/down Enable Clock 1 */
	__I	uint32_t	reserved0a0[4];
	__IO	uint32_t	test;		/* 0x0b0 Test */
} bcm2835_gpio_t;

/* BCM2835 SPI peripheral register map specification */
typedef struct __bcm2835_spi_t {
	__IO	uint32_t	cs;	/* 0x000 SPI Master Control and Status */
	__IO	uint32_t	fifo;	/* 0x004 SPI Master TX and RX FIFOs */
	__IO	uint32_t	clk;	/* 0x008 SPI Master Clock Divider */
	__IO	uint32_t	dlen;	/* 0x00c SPI Master Data Length */
	__IO	uint32_t	ltoh;	/* 0x010 SPI LOSSI mode TOH */
	__IO	uint32_t	dc;	/* 0x014 SPI DMA DREQ Controls */
} bcm2835_spi_t;


#define SPI_CS_LEN_LONG		0x02000000
#define SPI_CS_DMA_LEN		0x01000000
#define SPI_CS_CSPOL2		0x00800000
#define SPI_CS_CSPOL1		0x00400000
#define SPI_CS_CSPOL0		0x00200000
#define SPI_CS_RXF		0x00100000
#define SPI_CS_RXR		0x00080000
#define SPI_CS_TXD		0x00040000
#define SPI_CS_RXD		0x00020000
#define SPI_CS_DONE		0x00010000
#define SPI_CS_LEN		0x00002000
#define SPI_CS_REN		0x00001000
#define SPI_CS_ADCS		0x00000800
#define SPI_CS_INTR		0x00000400
#define SPI_CS_INTD		0x00000200
#define SPI_CS_DMAEN		0x00000100
#define SPI_CS_TA		0x00000080
#define SPI_CS_CSPOL		0x00000040
#define SPI_CS_CLEAR_RX		0x00000020
#define SPI_CS_CLEAR_TX		0x00000010
#define SPI_CS_CPOL		0x00000008
#define SPI_CS_CPHA		0x00000004
#define SPI_CS_CS_10		0x00000002
#define SPI_CS_CS_01		0x00000001

#endif

Attachment: hm2-7i90-stepper.hal
Description: application/vnd.hal

Attachment: hm2-stepper.hal
Description: application/vnd.hal

Attachment: 7i90-axis.ini
Description: application/wine-extension-ini

------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Emc-users mailing list
Emc-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/emc-users

Reply via email to