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
hm2-7i90-stepper.hal
Description: application/vnd.hal
hm2-stepper.hal
Description: application/vnd.hal
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