├── docs ├── pif2.pdf └── pif2_sch.pdf ├── software ├── src │ ├── pif.cpp │ ├── libpif.so │ ├── makefile │ ├── piffind.cpp │ ├── llbufs.h │ ├── lowlevel.h │ ├── pif.h │ ├── pifwrap.h │ ├── pifwrap.cpp │ ├── lowlevel.cpp │ ├── pifload.cpp │ └── bcm2835.c ├── templates │ ├── header.html │ ├── footer.html │ ├── layout.html │ └── index.html ├── static │ └── style.css ├── pifglobs.py ├── piffind.py ├── pifweb.py └── pifload.py ├── .gitattributes ├── firmware ├── pifcfg.vhd ├── flasher │ └── flasher.ldf ├── flashctl │ └── flashctl.ldf └── common │ ├── flasher.vhd │ ├── pifctl.vhd │ ├── flashctl.vhd │ ├── pif2.lpf │ ├── piffla.vhd │ ├── pifdefs.vhd │ ├── efb.vhd │ ├── pifwb.vhd │ └── flashctl_tb.vhd ├── .gitignore └── README.md /docs/pif2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugblat/pif2/HEAD/docs/pif2.pdf -------------------------------------------------------------------------------- /docs/pif2_sch.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugblat/pif2/HEAD/docs/pif2_sch.pdf -------------------------------------------------------------------------------- /software/src/pif.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugblat/pif2/HEAD/software/src/pif.cpp -------------------------------------------------------------------------------- /software/src/libpif.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bugblat/pif2/HEAD/software/src/libpif.so -------------------------------------------------------------------------------- /software/templates/header.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | $content.title 6 | $if content.cssfiles: 7 | $for f in content.cssfiles.split(): 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /software/templates/footer.html: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /software/templates/layout.html: -------------------------------------------------------------------------------- 1 | $def with (content) 2 | $# this is a comment 3 | 4 | 5 | 6 | 7 | $content.title 8 | $if content.cssfiles: 9 | $for f in content.cssfiles.split(): 10 | 11 | 12 | 13 |
14 | Change this header text to describe your pif project! 15 |
16 | 17 | $:content 18 | 19 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /software/templates/index.html: -------------------------------------------------------------------------------- 1 | $def with (state, form) 2 | $var title: pif Experiment 3 | $var cssfiles: static/style.css 4 | 5 |

Current LED state : $state

6 | $#
7 |
8 | $:form.render() 9 | 10 |
11 | 12 | $#
13 | $# 14 | $# 19 | $# 20 | $#
21 | -------------------------------------------------------------------------------- /software/src/makefile: -------------------------------------------------------------------------------- 1 | UNIFLAGS = -Wall -g -fPIC -I. -DBUILDING_LIBPIF -fvisibility=hidden 2 | CXX = g++ 3 | CXXFLAGS = -ansi $(UNIFLAGS) -fvisibility-inlines-hidden 4 | CC = gcc 5 | CCFLAGS = $(UNIFLAGS) 6 | 7 | DEPS = pif.h pifwrap.h lowlevel.h bcm2835.h llbufs.h 8 | OBJS = pif.o pifwrap.o lowlevel.o bcm2835.o 9 | TARGET = libpif.so 10 | LIBS = -lstdc++ 11 | LDFLAGS = -shared -Wl,-soname,$(TARGET) -fvisibility=hidden 12 | 13 | 14 | 15 | 16 | %.o : %.cpp $(DEPS) 17 | $(CXX) -c -o $@ $(CXXFLAGS) $< 18 | 19 | %.o : %.c $(DEPS) 20 | $(CC) -c -o $@ $(CCFLAGS) $< 21 | 22 | $(TARGET): $(OBJS) 23 | $(CXX) -o $@ $(OBJS) $(LDFLAGS) 24 | 25 | 26 | 27 | install: 28 | cp $(TARGET) /usr/lib 29 | chmod 0755 /usr/lib/$(TARGET) 30 | 31 | 32 | 33 | .PHONY: clean 34 | 35 | clean: 36 | rm -f *.o $(TARGET) 37 | -------------------------------------------------------------------------------- /firmware/pifcfg.vhd: -------------------------------------------------------------------------------- 1 | ----------------------------------------------------------------------- 2 | -- pifcfg.vhd, PIF_2 version 3 | -- 4 | -- Initial entry: 01-Mar-15 te 5 | -- non-common definitions to personalise the pif implementations 6 | -- 7 | ----------------------------------------------------------------------- 8 | library ieee; use ieee.std_logic_1164.all; 9 | 10 | package pifcfg is 11 | 12 | -- PIF_2 ID = 43h = 'C' 13 | constant PIF_ID : std_logic_vector(7 downto 0) := x"43"; -- 'C' 14 | constant XO2_DENSITY : string := "7000L"; 15 | 16 | end package pifcfg; 17 | 18 | ----------------------------------------------------------------------- 19 | package body pifcfg is 20 | end package body pifcfg; 21 | 22 | ----------------------------------------------------------------------- 23 | -- EOF pifcfg.vhd 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear in the root of a volume 35 | .DocumentRevisions-V100 36 | .fseventsd 37 | .Spotlight-V100 38 | .TemporaryItems 39 | .Trashes 40 | .VolumeIcon.icns 41 | 42 | # Directories potentially created on remote AFP share 43 | .AppleDB 44 | .AppleDesktop 45 | Network Trash Folder 46 | Temporary Items 47 | .apdisk 48 | -------------------------------------------------------------------------------- /software/src/piffind.cpp: -------------------------------------------------------------------------------- 1 | //--------------------------------------------------------------------- 2 | // piffind.cpp 3 | 4 | using namespace std; 5 | 6 | #include 7 | #include 8 | #include "pifwrap.h" 9 | 10 | //--------------------------------------------------------------------- 11 | int main() { 12 | char buff[200]; 13 | pifHandle h = NULL; 14 | printf("\n====================hello=========================="); 15 | h = pifInit(); 16 | printf("\nhandle=%x", (unsigned)h); 17 | 18 | pifVersion(buff, sizeof(buff)); 19 | printf("\n%s", buff); 20 | 21 | if (h) { 22 | uint32_t v = 99; 23 | bool x = getDeviceIdCode(h, &v); 24 | printf("\nresult=%d, ID code=%x", x, v); 25 | 26 | pifClose(h); 27 | } 28 | printf("\n==================== bye ==========================\n"); 29 | return 0; 30 | } 31 | 32 | // EOF ---------------------------------------------------------------- 33 | -------------------------------------------------------------------------------- /firmware/flasher/flasher.ldf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | PIF_2 - FPGA on a Raspberry Pi 2 | ============================== 3 | 4 | This is the software for Bugblat's PIF_2 *Raspberry Pi FPGA* board. 5 | 6 | The PIF_2 is 100% compatible with all Pi boards with a 40-pin 7 | connector - all reasonably recent Raspberry Pi models. 8 | It is bigger than the very small Pi Zero, a PIF_Z could be a better 9 | solution for that Pi model. 10 | 11 | What is the PIF_2 board? 12 | ------------------------ 13 | 14 | A pif board, which plugs into a Raspberry Pi, carries a non-volatile Lattice Semiconductor MachXO2 FPGA. 15 | 16 | To program the FPGA, you start by writing a firmware program, usually in VHDL or Verilog though there are other options. The firmware program can be simulated and compiled to a JEDEC bitstream with Lattice's free 17 | *[Diamond](http://www.latticesemi.com/en/Products/DesignSoftwareAndIP/FPGAandLDS/LatticeDiamond.aspx)* 18 | software. 19 | 20 | Then you have to inject the bitstream into the pif's FPGA, and that's the job of the software in this repo. Primarily in Python, there are programs to 21 | 22 | - program the onboard FPGA with a compiled bitstream 23 | - control the FPGA firmware from the Raspberry Pi processor 24 | 25 | Example FPGA firmware programs are also included, 26 | plus an example of controlling the FPGA from a web application. 27 | 28 | Many flavors of Linux are available for the Raspberry Pi. 29 | This software is written for the *Raspbian/jessie* distribution. 30 | 31 | More Information 32 | ---------------- 33 | 34 | The pif product pages, including links to the full documentation, are 35 | [here](http://bugblat.com/products/pif). 36 | -------------------------------------------------------------------------------- /software/static/style.css: -------------------------------------------------------------------------------- 1 | html, body 2 | { height : 100% 3 | ; width : 100% 4 | ; overflow : hidden 5 | ; font-family : verdana,arial,helvetica,sans-serif 6 | ; font-size : 14pt 7 | ; margin : 0 8 | ; padding : 0 9 | ; color : #808080 10 | ; background : #e6e6e6 11 | ; } 12 | 13 | header 14 | { height : 75px 15 | ; line-height : 75px 16 | ; vertical-align : middle 17 | ; position : relative 18 | ; width : 100% 19 | ; color : #eeeeee 20 | ; background : #b0b0b0 21 | ; border-bottom : 2px solid #e64e36 22 | ; text-align : center 23 | ; font-size : 22pt 24 | ; } 25 | 26 | footer 27 | { height : 44px 28 | ; line-height : 44px 29 | ; vertical-align : middle 30 | ; position : fixed 31 | ; width : 100% 32 | ; bottom : 0 33 | ; color : #474852 34 | ; background : #b0b0b0 35 | ; border-top : 2px solid #e64e36 36 | ; text-align : center 37 | ; } 38 | 39 | #current 40 | { height : 44px 41 | ; line-height : 44px 42 | ; vertical-align : middle 43 | ; color : #474852 44 | ; margin-left : 10% 45 | ; } 46 | 47 | table 48 | { height : 44px 49 | ; line-height : 44px 50 | ; vertical-align : middle 51 | ; color : #474852 52 | ; } 53 | 54 | form 55 | { height : 44px 56 | ; line-height : 44px 57 | ; vertical-align : middle 58 | ; margin-left : 10% 59 | ; } 60 | 61 | label 62 | { font-weight : normal 63 | ; } 64 | -------------------------------------------------------------------------------- /firmware/flashctl/flashctl.ldf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /software/src/llbufs.h: -------------------------------------------------------------------------------- 1 | // llbufs.h ---------------------------------------------------------- 2 | // 3 | // Copyright (c) 2001 to 2013 te 4 | // 5 | // Licence: Creative Commons Attribution-ShareAlike 3.0 Unported License. 6 | // http://creativecommons.org/licenses/by-sa/3.0/ 7 | //--------------------------------------------------------------------- 8 | #ifndef llbufsH 9 | #define llbufsH 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | //--------------------------------------------------------------------- 16 | #define LL_WR_BUFF_SIZE 64 /* CFG_PAGE_SIZE is 16 bytes */ 17 | class TllWrBuf { 18 | private: 19 | uint8_t Fbuf[LL_WR_BUFF_SIZE]; 20 | int Flen; 21 | 22 | public: 23 | TllWrBuf(int v) { clear(); byte(v); } 24 | TllWrBuf() { clear(); } 25 | 26 | TllWrBuf& clear() { 27 | Flen = 0; 28 | memset(Fbuf, 0, sizeof(Fbuf)); 29 | return *this; 30 | } 31 | TllWrBuf& byte(int v) { 32 | assert(Flen < LL_WR_BUFF_SIZE); 33 | Fbuf[Flen] = (uint8_t)v; 34 | Flen++; 35 | return *this; 36 | } 37 | TllWrBuf& wordLE(int v) { 38 | uint32_t x = v; 39 | byte(x); 40 | byte(x >> 8); 41 | return *this; 42 | } 43 | TllWrBuf& wordBE(int v) { 44 | uint32_t x = v; 45 | byte(x >> 8); 46 | byte(x); 47 | return *this; 48 | } 49 | TllWrBuf& dwordLE(int v) { 50 | uint32_t x = v; 51 | wordLE(x); 52 | wordLE(x >> 16); 53 | return *this; 54 | } 55 | TllWrBuf& dwordBE(int v) { 56 | uint32_t x = v; 57 | wordBE(x >> 16); 58 | wordBE(x); 59 | return *this; 60 | } 61 | 62 | uint8_t *data() { return Fbuf; } 63 | int length(){ return Flen; } 64 | }; 65 | #undef LL_WR_BUFF_SIZE 66 | 67 | #endif 68 | // EOF ---------------------------------------------------------------- 69 | -------------------------------------------------------------------------------- /software/src/lowlevel.h: -------------------------------------------------------------------------------- 1 | // lowlevel.h --------------------------------------------------------- 2 | // 3 | // Copyright (c) 2001 to 2013 te 4 | // 5 | // Licence: Creative Commons Attribution-ShareAlike 3.0 Unported License. 6 | // http://creativecommons.org/licenses/by-sa/3.0/ 7 | //--------------------------------------------------------------------- 8 | #ifndef lowlevelH 9 | #define lowlevelH 10 | 11 | #include 12 | #include "llbufs.h" 13 | 14 | #define MCP23008_ADDR 0x20 15 | 16 | #define I2C_CFG_ADDR 0x40 17 | #define I2C_APP_ADDR 0x41 18 | #define I2C_RST_ADDR 0x43 19 | 20 | #define RW_CONFIG true 21 | #define RW_APP (!RW_CONFIG) 22 | 23 | //--------------------------------------------------------------------- 24 | class TlowLevel { 25 | private: 26 | int Fi2cSlaveAddr; 27 | bool Finitialised; 28 | int FlastResult; 29 | 30 | void _setI2Caddr(int AslaveAddr); 31 | void _setSpiConfig(bool Aconfig); 32 | 33 | public: 34 | //------------------------------------------- 35 | bool i2cWrite(int AslaveAddr, const uint8_t *pWrData, size_t AwrLen); 36 | bool i2cRead(int AslaveAddr, uint8_t *pRdData, size_t ArdLen); 37 | bool i2cWriteRead(int AslaveAddr, const uint8_t *pWrData, 38 | uint8_t *pRdData, size_t ArdLen); 39 | 40 | bool spiWrite(bool aConfig, const uint8_t *pWrData, size_t AwrLen); 41 | bool spiRead(bool aConfig, uint8_t *pRdData, size_t ArdLen); 42 | bool spiWriteRead(bool aConfig, const uint8_t *pWrData, size_t AwrLen, 43 | uint8_t *pRdData, size_t ArdLen); 44 | int lastReturnCode() { return FlastResult; } 45 | 46 | //------------------------------------------- 47 | TlowLevel(); 48 | ~TlowLevel(); 49 | }; 50 | 51 | #endif 52 | 53 | // EOF ---------------------------------------------------------------- 54 | -------------------------------------------------------------------------------- /firmware/common/flasher.vhd: -------------------------------------------------------------------------------- 1 | ----------------------------------------------------------------------- 2 | -- flasher.vhd 3 | -- 4 | -- Initial entry: 21-Apr-11 te 5 | -- 6 | -- VHDL hierarchy is 7 | -- flasher top level 8 | -- piffla.vhd does the work! 9 | -- 10 | ----------------------------------------------------------------------- 11 | -- 12 | -- Copyright (c) 2001 to 2013 te 13 | -- 14 | ----------------------------------------------------------------------- 15 | library IEEE; use IEEE.std_logic_1164.all; 16 | library machxo2; use machxo2.components.all; 17 | 18 | --===================================================================== 19 | entity flasher is 20 | port ( GSRn : in std_logic; 21 | LEDR, 22 | LEDG : out std_logic ); 23 | end flasher; 24 | 25 | --===================================================================== 26 | architecture rtl of flasher is 27 | ----------------------------------------------- 28 | component pif_flasher is port ( red, green : out std_logic ); 29 | end component pif_flasher; 30 | ----------------------------------------------- 31 | 32 | signal red_flash, 33 | green_flash : std_logic; 34 | 35 | signal GSRnX : std_logic; 36 | attribute pullmode : string; 37 | attribute pullmode of GSRnX: signal is "UP"; -- else floats 38 | 39 | begin 40 | -- global reset 41 | IBgsr : IB port map ( I=>GSRn, O=>GSRnX ); 42 | GSR_GSR : GSR port map ( GSR=>GSRnX ); 43 | 44 | ----------------------------------------------- 45 | -- LED flasher 46 | F: pif_flasher port map ( red => red_flash, 47 | green => green_flash ); 48 | 49 | ----------------------------------------------- 50 | -- drive the LEDs 51 | REDL: OB port map ( I=>red_flash , O => LEDR ); 52 | GRNL: OB port map ( I=>green_flash, O => LEDG ); 53 | 54 | end rtl; 55 | -- EOF ---------------------------------------------------------------- 56 | -------------------------------------------------------------------------------- /software/pifglobs.py: -------------------------------------------------------------------------------- 1 | ##--------------------------------------------------------- 2 | # Name: pifglobs.py 3 | # Purpose: globals 4 | # 5 | # Author: Tim 6 | # 7 | # Created: 08/07/2013 8 | # Copyright: (c) Tim 2013 9 | # Licence: Creative Commons Attribution-ShareAlike 3.0 Unported License. 10 | ##--------------------------------------------------------- 11 | 12 | ##--------------------------------------------------------- 13 | # MCP23008 GP I/O assignments 14 | 15 | MCP_FPGA_TDO = 0 16 | MCP_FPGA_TDI = 1 17 | MCP_FPGA_TCK = 2 18 | MCP_FPGA_TMS = 3 19 | MCP_FPGA_JTAGENn = 4 ## JTAGENA 20 | MCP_FPGA_PROGn = 5 21 | MCP_FPGA_INITn = 6 22 | MCP_FPGA_DONE = 7 23 | 24 | ##--------------------------------------------------------- 25 | # XO2 configuration memory 26 | CFG_PAGE_SIZE = 16 27 | UFM_PAGE_SIZE = 16 28 | 29 | ## XO2-1200 30 | CFG_PAGE_COUNT_1200 = 2175 31 | UFM_PAGE_COUNT_1200 = 512 32 | 33 | ## XO2-2000 34 | CFG_PAGE_COUNT_2000 = 3198 35 | UFM_PAGE_COUNT_2000 = 640 36 | 37 | ## XO2-4000 38 | CFG_PAGE_COUNT_4000 = 5758 39 | UFM_PAGE_COUNT_4000 = 768 40 | 41 | ## XO2-7000 42 | CFG_PAGE_COUNT_7000 = 9212 43 | UFM_PAGE_COUNT_7000 = 2048 44 | 45 | UNRECOGNIZED = 'unrecognized' 46 | 47 | ##--------------------------------------------------------- 48 | # register addresses. 49 | # these _must_ match the addresses defined for the hardware in pifdefs.vhd 50 | 51 | # read-only ID register 52 | R_ID = 0 53 | 54 | # write-only Scratch and Misc registers 55 | W_SCRATCH_REG = 1 56 | W_MISC_REG = 2 57 | 58 | # misc register LED control values 59 | LED_ALTERNATING = 0 60 | LED_SYNC = 1 61 | LED_OFF = 2 62 | 63 | ##--------------------------------------------------------- 64 | # write command format 65 | # the basic idea is to send an address, followed by a series of data values 66 | # both address and data are six bit values 67 | # the byte format is as follows, two top bits ssignal address or data 68 | # bit number 76543210 69 | # address format 00aaaaaa aaaaaa is the register address 70 | # data format 01dddddd dddddd is the data for the register 71 | 72 | ADDRESS_MASK = 0 73 | DATA_MASK = 0x40 74 | 75 | ##--------------------------------------------------------- 76 | STR_LEDS_ALT = 'alternating' 77 | STR_LEDS_SYNC = 'synchronized' 78 | STR_LEDS_OFF = 'off' 79 | 80 | # EOF ----------------------------------------------------- 81 | -------------------------------------------------------------------------------- /software/piffind.py: -------------------------------------------------------------------------------- 1 | #---------------------------------------------------------------------- 2 | # Name: piffind.py 3 | # Purpose: sarch for the XO2 via the smbus Python library 4 | # 5 | # Author: Tim 6 | # 7 | # Created: 11/07/2012 8 | # Copyright: (c) Tim 2013 9 | # Licence: Creative Commons Attribution-ShareAlike 3.0 Unported License. 10 | #---------------------------------------------------------------------- 11 | #!/usr/bin/env python 12 | 13 | # import ptvsd 14 | # ptvsd.enable_attach('moi') 15 | # import rpdb2 16 | # rpdb2.start_embedded_debugger('pw') 17 | 18 | import sys, ctypes, pifglobs 19 | from ctypes import * 20 | from pifglobs import * 21 | 22 | ##--------------------------------------------------------- 23 | def showDeviceID(handle): 24 | 25 | dw = c_ulong(0xdeadbeef) 26 | res = pifglobs.pif.pifGetDeviceIdCode(handle, byref(dw)) 27 | if (res == 0): 28 | print("\nread ID code failed\n") 29 | return "failed" 30 | 31 | deviceID = dw.value 32 | print('XO2 Device ID: %08x' % deviceID) , 33 | 34 | s = UNRECOGNIZED 35 | ok = (deviceID & 0xffff8fff) == (0x012ba043 & 0xffff8fff) 36 | model = (deviceID >> 12) & 7; 37 | 38 | if model == 0 : 39 | s = "XO2-256HC" 40 | elif model == 1 : 41 | s = "XO2-640HC" 42 | elif model == 2 : 43 | s = "XO2-1200HC" 44 | elif model == 3 : 45 | s = "XO2-2000HC" 46 | elif model == 4 : 47 | s = "XO2-4000HC" 48 | elif model == 5 : 49 | s = "XO2-7000HC" 50 | else: 51 | s = UNRECOGNIZED 52 | ok = false; 53 | 54 | if ok == True: 55 | print(" - device is an " + s) 56 | else: 57 | print(" - unrecognised ID!") 58 | 59 | return s; 60 | 61 | ##--------------------------------------------------------- 62 | def main(): 63 | print("================= pif find ========================") 64 | handle = None 65 | ## tmp = int(input('type some num: ')) ## debugger process pause 66 | 67 | try: 68 | pifglobs.pif = ctypes.CDLL("libpif.so") 69 | 70 | strBuf = create_string_buffer(1000) 71 | rv = pifglobs.pif.pifVersion(strBuf, sizeof(strBuf)) 72 | print('Using pif library version: %s\n' % repr(strBuf.value)) 73 | 74 | handle = c_int(pifglobs.pif.pifInit()) 75 | dev = showDeviceID(handle) 76 | 77 | except: 78 | e = sys.exc_info()[0] 79 | print("\nException caught %s\n" % e) 80 | 81 | if handle: 82 | pifglobs.pif.pifClose(handle) 83 | print("\n==================== bye ==========================") 84 | 85 | ##--------------------------------------------------------- 86 | if __name__ == '__main__': 87 | main() 88 | 89 | # EOF ----------------------------------------------------------------- 90 | 91 | -------------------------------------------------------------------------------- /software/src/pif.h: -------------------------------------------------------------------------------- 1 | // pif.h ------------------------------------------------------------- 2 | // 3 | // Copyright (c) 2001 to 2013 te 4 | // 5 | // Licence: Creative Commons Attribution-ShareAlike 3.0 Unported License. 6 | // http://creativecommons.org/licenses/by-sa/3.0/ 7 | //--------------------------------------------------------------------- 8 | #ifndef pifH 9 | #define pifH 10 | 11 | #include "lowlevel.h" 12 | 13 | #define CFG_PAGE_SIZE 16 14 | #define UFM_PAGE_SIZE 16 15 | #define CFG_PAGE_COUNT 2175 16 | #define UFM_PAGE_COUNT 512 17 | 18 | #define FEATURE_ERASE (1<<1) 19 | #define CFG_ERASE (1<<2) 20 | #define UFM_ERASE (1<<3) 21 | 22 | #define DEFAULT_BUSY_LOOPS 5 23 | 24 | #define A_ADDR (0<<6) /* sending an address */ 25 | #define D_ADDR (1<<6) /* sending data */ 26 | 27 | class TlowLevel; 28 | 29 | //--------------------------------------------------------------------- 30 | class Tpif { 31 | private: 32 | TlowLevel *pLo; 33 | 34 | uint32_t _dwordBE(uint8_t *p); 35 | bool _cfgWrite(TllWrBuf& oBuf); 36 | bool _cfgWriteRead(TllWrBuf& oBuf, uint8_t *pRdData, size_t ArdLen); 37 | 38 | bool _doSimple(int Acmd, int Ap0=0); 39 | 40 | bool _progPage(int Acmd, const uint8_t *p); 41 | bool _readPages(int Acmd, int numPages, uint8_t *p); 42 | bool _readPage(int Acmd, uint8_t *p); 43 | 44 | bool _initUfmAddr(); 45 | bool _setUfmPageAddr(int pageNumber); 46 | bool _progUfmPage(const uint8_t *p); 47 | 48 | bool _isBusy(); 49 | 50 | void shortSleep(int ns); 51 | 52 | public: 53 | bool getDeviceIdCode(uint32_t& v); 54 | 55 | bool getStatusReg(uint32_t& v); 56 | bool getTraceId(uint8_t* p); 57 | 58 | bool enableCfgInterfaceOffline(); 59 | bool enableCfgInterfaceTransparent(); 60 | bool disableCfgInterface(); 61 | bool refresh(); 62 | bool progDone(); 63 | 64 | bool erase(int Amask); 65 | bool eraseAll(); 66 | 67 | bool initCfgAddr(); 68 | bool eraseCfg(); 69 | bool progCfgPage(const uint8_t *p); 70 | bool readCfgPages(int numPages, uint8_t *p); 71 | 72 | bool eraseUfm(); 73 | bool readUfmPages(int numPages, uint8_t *p); 74 | bool readUfmPages(int pageNumber, int numPages, uint8_t *p); 75 | bool writeUfmPages(int pageNumber, int numPages, uint8_t *p); 76 | 77 | bool getBusyFlag(int *pFlag); 78 | bool waitUntilNotBusy(int maxLoops=DEFAULT_BUSY_LOOPS); 79 | 80 | bool setUsercode(uint8_t* p); 81 | bool getUsercode(uint8_t* p); 82 | 83 | bool mcpWrite(uint8_t* p, int len); 84 | bool mcpRead(int reg, uint8_t* v); 85 | 86 | //--------------------- 87 | bool appRead(uint8_t *p, int AnumBytes); 88 | bool appWrite(uint8_t *p, int AnumBytes); 89 | 90 | Tpif(); 91 | ~Tpif(); 92 | }; 93 | 94 | #endif 95 | // EOF ---------------------------------------------------------------- 96 | -------------------------------------------------------------------------------- /firmware/common/pifctl.vhd: -------------------------------------------------------------------------------- 1 | ----------------------------------------------------------------------- 2 | -- pifctl.vhd Bugblat pif central control logic 3 | -- 4 | -- Initial entry: 31-May-13 te 5 | -- Copyright (c) 2001 to 2013 te 6 | -- 7 | ----------------------------------------------------------------------- 8 | library ieee; use ieee.std_logic_1164.all; 9 | use ieee.numeric_std.all; 10 | library work; use work.defs.all; 11 | 12 | entity pifctl is 13 | port (xclk : in std_logic; 14 | XI : in XIrec; 15 | XO : out slv8; 16 | MiscReg : out TMisc ); 17 | end pifctl; 18 | 19 | architecture rtl of pifctl is 20 | 21 | signal ScratchReg : TwrData := n2slv(21, I2C_DATA_BITS); -- 15h 22 | signal MiscRegLocal : TMisc := LED_SYNC; 23 | 24 | begin 25 | --------------------------------------------------------------------- 26 | -- the inner case statement can be extended to write to many registers 27 | process (xclk) 28 | begin 29 | if rising_edge(xclk) then 30 | if XI.PWr then 31 | case XI.PRWA is 32 | 33 | when W_SCRATCH_REG => 34 | ScratchReg <= XI.PD; 35 | 36 | when W_MISC_REG => 37 | MiscRegLocal <= ToInteger(XI.PD); 38 | 39 | when others => null; 40 | end case; 41 | end if; 42 | end if; 43 | end process; 44 | 45 | --------------------------------------------------------------------- 46 | -- readout to the wishbone controller 47 | READBACK: block 48 | signal IdReadback : slv8; 49 | begin 50 | ----------------------------------------------- 51 | -- ID/Scratch/Misc register readback 52 | process (xclk) 53 | variable subAddr : integer range R_ID_NUM_SUBS-1 downto 0; 54 | variable IDscratch 55 | , IDletter 56 | , subOut 57 | , regOut : slv8; 58 | begin 59 | if rising_edge(xclk) then 60 | IDscratch := "01" & ScratchReg; 61 | IDletter := n2slv(6, 4) & n2slv(XI.PRdSubA, 4); -- 61h='a'... 62 | 63 | subAddr := XI.PRdSubA mod R_ID_NUM_SUBS; 64 | 65 | subOut := IDletter; 66 | 67 | if (subAddr = R_ID_ID) then 68 | subOut := ID; 69 | end if; 70 | if (subAddr = R_ID_SCRATCH) then 71 | subOut := IDscratch; 72 | end if; 73 | if (subAddr = R_ID_MISC) then 74 | subOut := n2slv(5, 4) & n2slv(MiscRegLocal, 4); -- 50h='P'... 75 | end if; 76 | 77 | regOut := (others=>'0'); 78 | if (XI.PRWA = R_ID) then 79 | regOut := subOut; 80 | end if; 81 | 82 | IdReadback <= regOut; 83 | end if; 84 | end process; 85 | 86 | XO <= IdReadback; 87 | MiscReg <= MiscRegLocal; 88 | 89 | end block READBACK; 90 | 91 | end rtl; 92 | 93 | ----------------------------------------------------------------------- 94 | -- EOF pifctl.vhd 95 | -------------------------------------------------------------------------------- /software/src/pifwrap.h: -------------------------------------------------------------------------------- 1 | // pifwrap.h ---------------------------------------------------------- 2 | // 3 | // Copyright (c) 2001 to 2013 te 4 | // 5 | // a C wrapper for the pif code 6 | // 7 | // Licence: Creative Commons Attribution-ShareAlike 3.0 Unported License. 8 | // http://creativecommons.org/licenses/by-sa/3.0/ 9 | //--------------------------------------------------------------------- 10 | #ifndef pifwrapH 11 | #define pifwrapH 12 | 13 | #include 14 | 15 | #if defined _WIN32 || defined __CYGWIN__ 16 | #define PIF_DLL_IMPORT __declspec(dllimport) 17 | #define PIF_DLL_EXPORT __declspec(dllexport) 18 | #define PIF_DLL_LOCAL 19 | #else 20 | #if __GNUC__ >= 4 21 | #define PIF_DLL_IMPORT __attribute__ ((visibility ("default"))) 22 | #define PIF_DLL_EXPORT __attribute__ ((visibility ("default"))) 23 | #define PIF_DLL_LOCAL __attribute__ ((visibility ("hidden"))) 24 | #else 25 | #define PIF_DLL_IMPORT 26 | #define PIF_DLL_EXPORT 27 | #define PIF_DLL_LOCAL 28 | #endif 29 | #endif 30 | 31 | // Add '-DBUILDING_LIBPIF' and '-fvisibility=hidden' to the makefile flags 32 | 33 | #if BUILDING_LIBPIF // && HAVE_VISIBILITY 34 | #define PIF_API extern PIF_DLL_EXPORT 35 | #else 36 | #define PIF_API extern 37 | #endif 38 | 39 | typedef void * pifHandle; 40 | 41 | //--------------------------------------------------------------------- 42 | #ifdef __cplusplus 43 | extern "C" { 44 | #endif 45 | PIF_API int pifVersion(char *outStr, int outLen); 46 | 47 | PIF_API int pifGetDeviceIdCode(pifHandle h, uint32_t* v); 48 | 49 | PIF_API int pifGetStatusReg(pifHandle h, uint32_t* v); 50 | PIF_API int pifGetTraceId(pifHandle h, uint8_t* p); 51 | 52 | PIF_API int pifEnableCfgInterfaceOffline(pifHandle h); 53 | PIF_API int pifEnableCfgInterfaceTransparent(pifHandle h); 54 | PIF_API int pifDisableCfgInterface(pifHandle h); 55 | PIF_API int pifRefresh(pifHandle h); 56 | PIF_API int pifProgDone(pifHandle h); 57 | 58 | PIF_API int pifErase(pifHandle h, int Amask); 59 | PIF_API int pifEraseAll(pifHandle h); 60 | 61 | PIF_API int pifInitCfgAddr(pifHandle h); 62 | PIF_API int pifEraseCfg(pifHandle h); 63 | PIF_API int pifProgCfgPage(pifHandle h, const uint8_t *p); 64 | PIF_API int pifReadCfgPages(pifHandle h, int numPages, uint8_t *p); 65 | 66 | PIF_API int pifEraseUfm(pifHandle h); 67 | PIF_API int pifReadUfmPages(pifHandle h, int pageNumber, int numPages, uint8_t *p); 68 | PIF_API int pifWriteUfmPages(pifHandle h, int pageNumber, int numPages, uint8_t *p); 69 | 70 | PIF_API int pifGetBusyFlag(pifHandle h, int *pFlag); 71 | PIF_API int pifWaitUntilNotBusy(pifHandle h, int maxLoops); 72 | 73 | PIF_API int pifSetUsercode(pifHandle h, uint8_t* p); 74 | PIF_API int pifGetUsercode(pifHandle h, uint8_t* p); 75 | 76 | //--------------------- 77 | PIF_API int pifMcpWrite(pifHandle h, uint8_t* p, int len); 78 | PIF_API int pifMcpRead(pifHandle h, int reg, uint8_t* v); 79 | 80 | //--------------------- 81 | PIF_API int pifAppRead(pifHandle h, uint8_t *p, int AnumBytes); 82 | PIF_API int pifAppWrite(pifHandle h, uint8_t *p, int AnumBytes); 83 | 84 | PIF_API pifHandle pifInit(); 85 | PIF_API void pifClose(pifHandle h); 86 | 87 | #ifdef __cplusplus 88 | } 89 | #endif 90 | 91 | #endif 92 | // EOF ---------------------------------------------------------------- 93 | -------------------------------------------------------------------------------- /software/src/pifwrap.cpp: -------------------------------------------------------------------------------- 1 | // pifwrap.cpp -------------------------------------------------------- 2 | // 3 | // Copyright (c) 2001 to 2013 te 4 | // 5 | // a C wrapper for the pif code 6 | // 7 | // Licence: Creative Commons Attribution-ShareAlike 3.0 Unported License. 8 | // http://creativecommons.org/licenses/by-sa/3.0/ 9 | //--------------------------------------------------------------------- 10 | #if defined(_WIN32) 11 | #define _CRT_SECURE_NO_WARNINGS // Disable deprecation warning in VS2005 12 | #else 13 | #define _XOPEN_SOURCE 600 // For PATH_MAX on linux 14 | #endif 15 | 16 | #include 17 | 18 | #include "pifwrap.h" 19 | #include "pif.h" 20 | 21 | #define pPif ((Tpif *)h) 22 | 23 | //--------------------------------------------------------------------- 24 | int pifVersion(char *outStr, int outLen) { 25 | if (outLen<=0) 26 | return 0; 27 | const char * retval = (const char *)("libpif," __DATE__ "," __TIME__); 28 | int retlen = strlen(retval); 29 | strncpy(outStr, retval, outLen); 30 | outStr[outLen-1] = 0; 31 | return retlen; 32 | } 33 | 34 | int pifGetDeviceIdCode(pifHandle h, uint32_t* v) { 35 | return pPif->getDeviceIdCode(*v); 36 | } 37 | int pifGetStatusReg(pifHandle h, uint32_t* v) { 38 | return pPif->getStatusReg(*v); 39 | } 40 | int pifGetTraceId(pifHandle h, uint8_t* p) { 41 | return pPif->getTraceId(p); 42 | } 43 | int pifEnableCfgInterfaceOffline(pifHandle h) { 44 | return pPif->enableCfgInterfaceOffline(); 45 | } 46 | int pifEnableCfgInterfaceTransparent(pifHandle h) { 47 | return pPif->enableCfgInterfaceTransparent(); 48 | } 49 | int pifDisableCfgInterface(pifHandle h) { 50 | return pPif->disableCfgInterface(); 51 | } 52 | int pifRefresh(pifHandle h) { 53 | return pPif->refresh(); 54 | } 55 | int pifProgDone(pifHandle h) { 56 | return pPif->progDone(); 57 | } 58 | int pifErase(pifHandle h, int Amask) { 59 | return pPif->erase(Amask); 60 | } 61 | int pifEraseAll(pifHandle h) { 62 | return pPif->eraseAll(); 63 | } 64 | int pifInitCfgAddr(pifHandle h) { 65 | return pPif->initCfgAddr(); 66 | } 67 | int pifEraseCfg(pifHandle h) { 68 | return pPif->eraseCfg(); 69 | } 70 | int pifProgCfgPage(pifHandle h, const uint8_t *p) { 71 | return pPif->progCfgPage(p); 72 | } 73 | int pifReadCfgPages(pifHandle h, int numPages, uint8_t *p) { 74 | return pPif->readCfgPages(numPages, p); 75 | } 76 | int pifEraseUfm(pifHandle h) { 77 | return pPif->eraseUfm(); 78 | } 79 | int pifReadUfmPages(pifHandle h, int numPages, uint8_t *p) { 80 | return pPif->readUfmPages(numPages, p); 81 | } 82 | int pifReadUfmPages(pifHandle h, int pageNumber, int numPages, uint8_t *p) { 83 | return pPif->readUfmPages(pageNumber, numPages, p); 84 | } 85 | int pifWriteUfmPages(pifHandle h, int pageNumber, int numPages, uint8_t *p) { 86 | return pPif->writeUfmPages(pageNumber, numPages, p); 87 | } 88 | int pifGetBusyFlag(pifHandle h, int *pFlag) { 89 | return pPif->getBusyFlag(pFlag); 90 | } 91 | int pifWaitUntilNotBusy(pifHandle h, int maxLoops) { 92 | return pPif->waitUntilNotBusy(maxLoops); 93 | } 94 | int pifSetUsercode(pifHandle h, uint8_t* p) { 95 | return pPif->setUsercode(p); 96 | } 97 | int pifGetUsercode(pifHandle h, uint8_t* p) { 98 | return pPif->getUsercode(p); 99 | } 100 | 101 | int pifMcpWrite(pifHandle h, uint8_t* p, int len) { 102 | return pPif->mcpWrite(p, len); 103 | } 104 | int pifMcpRead(pifHandle h, int reg, uint8_t* v) { 105 | return pPif->mcpRead(reg, v); 106 | } 107 | 108 | int pifAppRead(pifHandle h, uint8_t *p, int AnumBytes) { 109 | return pPif->appRead(p, AnumBytes); 110 | } 111 | int pifAppWrite(pifHandle h, uint8_t *p, int AnumBytes) { 112 | return pPif->appWrite(p, AnumBytes); 113 | } 114 | 115 | pifHandle pifInit() { 116 | return (pifHandle)(new Tpif()); 117 | } 118 | void pifClose(pifHandle h) { 119 | delete pPif; 120 | } 121 | 122 | // EOF ---------------------------------------------------------------- 123 | -------------------------------------------------------------------------------- /firmware/common/flashctl.vhd: -------------------------------------------------------------------------------- 1 | ----------------------------------------------------------------------- 2 | -- flashctl.vhd 3 | -- 4 | -- Initial entry: 21-Apr-11 te 5 | -- 6 | -- VHDL hierarchy is 7 | -- flasher top level 8 | -- piffla.vhd does the work! 9 | -- pifwb.vhd wishbone interface 10 | -- efb.vhd XO2 embedded function block 11 | -- 12 | ----------------------------------------------------------------------- 13 | -- 14 | -- Copyright (c) 2001 to 2013 te 15 | -- 16 | ----------------------------------------------------------------------- 17 | library IEEE; use IEEE.std_logic_1164.all; 18 | library work; use work.defs.all; 19 | library machxo2; use machxo2.components.all; 20 | 21 | --===================================================================== 22 | entity flasher is 23 | port ( SCL, 24 | SDA : inout std_logic; 25 | GSRn : in std_logic; 26 | LEDR, 27 | LEDG : out std_logic ); 28 | end flasher; 29 | 30 | --===================================================================== 31 | architecture rtl of flasher is 32 | ----------------------------------------------- 33 | component pif_flasher is port ( 34 | red, 35 | green, 36 | xclk : out std_logic ); 37 | end component pif_flasher; 38 | ----------------------------------------------- 39 | component pifwb is port ( 40 | i2c_SCL : inout std_logic; 41 | i2c_SDA : inout std_logic; 42 | xclk : in std_logic; 43 | XI : out XIrec; 44 | XO : in slv8 ); 45 | end component pifwb; 46 | ----------------------------------------------- 47 | component pifctl is port ( 48 | xclk : in std_logic; 49 | XI : in XIrec; 50 | XO : out slv8; 51 | MiscReg : out TMisc ); 52 | end component pifctl; 53 | ----------------------------------------------- 54 | 55 | signal red_flash, 56 | green_flash, 57 | xclk : std_logic := '0'; 58 | signal XI : XIrec := ( PRdFinished => false 59 | , PWr => false 60 | , PRWA => 0 61 | , PRdSubA => 0 62 | , PD => (others=>'0')); 63 | signal XO : slv8 := (others=>'0'); 64 | 65 | signal GSRnX : std_logic; 66 | signal MiscReg : TMisc; 67 | 68 | -- attach a pullup to the GSRn signal 69 | attribute pullmode : string; 70 | attribute pullmode of GSRnX : signal is "UP"; -- else floats 71 | 72 | begin 73 | -- global reset 74 | IBgsr : IB port map ( I=>GSRn, O=>GSRnX ); 75 | GSR_GSR : GSR port map ( GSR=>GSRnX ); 76 | 77 | ----------------------------------------------- 78 | -- wishbone interface 79 | WB: pifwb port map ( i2c_SCL => SCL, 80 | i2c_SDA => SDA, 81 | xclk => xclk, 82 | XI => XI, 83 | XO => XO ); 84 | 85 | ----------------------------------------------- 86 | -- LED flasher 87 | F: pif_flasher port map ( red => red_flash, 88 | green => green_flash, 89 | xclk => xclk ); 90 | 91 | ----------------------------------------------- 92 | -- control logic 93 | TC: pifctl port map ( xclk => xclk, 94 | XI => XI, 95 | XO => XO, 96 | MiscReg => MiscReg ); 97 | 98 | ----------------------------------------------- 99 | -- drive the LEDs 100 | LED_BLOCK : block 101 | signal r,g : std_logic; 102 | begin 103 | r <= red_flash when MiscReg=LED_ALTERNATING else 104 | red_flash when MiscReg=LED_SYNC else 105 | '0'; 106 | g <= green_flash when MiscReg=LED_ALTERNATING else 107 | red_flash when MiscReg=LED_SYNC else 108 | '0'; 109 | RED_BUF: OB port map ( I=>r, O => LEDR ); 110 | GRN_BUF: OB port map ( I=>g, O => LEDG ); 111 | end block LED_BLOCK; 112 | 113 | end rtl; 114 | -- EOF ---------------------------------------------------------------- 115 | -------------------------------------------------------------------------------- /software/pifweb.py: -------------------------------------------------------------------------------- 1 | ##--------------------------------------------------------- 2 | # Name: pifweb.py 3 | # Purpose: control a pif board via a web server 4 | # 5 | # Author: Tim 6 | # 7 | # Created: 08/07/2013 8 | # Copyright: (c) Tim 2013 9 | # Licence: Creative Commons Attribution-ShareAlike 3.0 Unported License. 10 | ##--------------------------------------------------------- 11 | # uses web.py - see www.webpy.org 12 | # 13 | # windows command line start: python pifweb.py 14 | # 15 | #!/usr/bin/env python 16 | 17 | import sys, web, ctypes, pifglobs 18 | from web import form 19 | from ctypes import * 20 | from pifglobs import * 21 | 22 | ##--------------------------------------------------------- 23 | def showDeviceID(handle): 24 | 25 | dw = c_ulong(0xdeadbeef) 26 | res = pifglobs.pif.pifGetDeviceIdCode(handle, byref(dw)) 27 | if (res == 0): 28 | print("\nread ID code failed\n") 29 | return "failed" 30 | 31 | deviceID = dw.value 32 | print('XO2 Device ID: %08x' % deviceID) , 33 | 34 | s = UNRECOGNIZED 35 | ok = (deviceID & 0xffff8fff) == (0x012ba043 & 0xffff8fff) 36 | model = (deviceID >> 12) & 7; 37 | 38 | if model == 0 : 39 | s = "XO2-256HC" 40 | elif model == 1 : 41 | s = "XO2-640HC" 42 | elif model == 2 : 43 | s = "XO2-1200HC" 44 | elif model == 3 : 45 | s = "XO2-2000HC" 46 | elif model == 4 : 47 | s = "XO2-4000HC" 48 | elif model == 5 : 49 | s = "XO2-7000HC" 50 | else: 51 | s = UNRECOGNIZED 52 | ok = false; 53 | 54 | if ok == True: 55 | print(" - device is an " + s) 56 | else: 57 | print(" - unrecognised ID!") 58 | 59 | return s; 60 | 61 | ##--------------------------------------------------------- 62 | def sendAddressByte(handle, a): 63 | try: 64 | cmdLength = 1 65 | buff = create_string_buffer(chr(ADDRESS_MASK | a), cmdLength) 66 | numWritten = c_ulong(0) 67 | res = pifglobs.pif.pifAppWrite(handle, buff, cmdLength, byref(numWritten)) 68 | except: 69 | print('FAILED: address byte send') 70 | 71 | ##--------------------------------------------------------- 72 | def sendDataByte(handle, v): 73 | try: 74 | cmdLength = 1 75 | buff = create_string_buffer(chr(DATA_MASK | v), cmdLength) 76 | numWritten = c_ulong(0) 77 | res = pifglobs.pif.pifAppWrite(handle, buff, cmdLength, byref(numWritten)) 78 | except: 79 | print('FAILED: data byte send') 80 | 81 | ##--------------------------------------------------------- 82 | # write val into the Misc register inside the FPGA 83 | def setMiscRegister(val): 84 | try: 85 | sendAddressByte(pifglobs.handle, W_MISC_REG) 86 | sendDataByte(pifglobs.handle, val) 87 | except: 88 | pass 89 | 90 | ##--------------------------------------------------------- 91 | urls = ('/', 'index') 92 | render = web.template.render('templates/', base='layout') 93 | tag = 'Red and Green LEDs ' 94 | myform = web.form.Form( 95 | form.Dropdown(tag, [STR_LEDS_ALT, STR_LEDS_SYNC, STR_LEDS_OFF])) 96 | 97 | class index: 98 | def GET(self): 99 | form = myform() 100 | return render.index(pifglobs.state, form) 101 | 102 | def POST(self): 103 | form = myform() 104 | if form.validates(): 105 | pifglobs.state = form[tag].value 106 | if pifglobs.state==STR_LEDS_ALT: 107 | setMiscRegister(LED_ALTERNATING) 108 | elif pifglobs.state==STR_LEDS_SYNC: 109 | setMiscRegister(LED_SYNC) 110 | elif pifglobs.state==STR_LEDS_OFF: 111 | setMiscRegister(LED_OFF) 112 | return render.index(pifglobs.state, form) 113 | 114 | ##--------------------------------------------------------- 115 | def main(): 116 | handle = None 117 | try: 118 | pifglobs.pif = ctypes.CDLL("libpif.so") 119 | 120 | strBuf = create_string_buffer(1000) 121 | rv = pifglobs.pif.pifVersion(strBuf, sizeof(strBuf)) 122 | print('Using pif library version: %s\n' % repr(strBuf.value)) 123 | 124 | handle = c_int(pifglobs.pif.pifInit()) 125 | dev = showDeviceID(handle) 126 | 127 | if dev != UNRECOGNIZED: 128 | print('pif detected') 129 | pifglobs.handle = handle 130 | pifglobs.state = STR_LEDS_ALT 131 | setMiscRegister(LED_ALTERNATING) 132 | app = web.application(urls, globals()) 133 | app.run() 134 | 135 | except: 136 | e = sys.exc_info()[0] 137 | print("\nException caught %s\n" % e) 138 | 139 | if handle: 140 | pifglobs.pif.pifClose(handle) 141 | 142 | ##--------------------------------------------------------- 143 | if __name__ == '__main__': 144 | main() 145 | 146 | # EOF ----------------------------------------------------------------- 147 | -------------------------------------------------------------------------------- /firmware/common/pif2.lpf: -------------------------------------------------------------------------------- 1 | # PIF_2 preferences 2 | # 3 | # first written: 26-Mar-2015 4 | # 5 | ################################################# 6 | 7 | BLOCK RESETPATHS ; 8 | BLOCK ASYNCPATHS ; 9 | 10 | BANK 0 VCCIO 3.3 V; 11 | BANK 1 VCCIO 3.3 V; 12 | BANK 2 VCCIO 3.3 V; 13 | BANK 3 VCCIO 3.3 V; 14 | BANK 5 VCCIO 3.3 V; 15 | BANK 6 VCCIO 3.3 V; 16 | 17 | TRACEID "00111100" ; 18 | 19 | IOBUF ALLPORTS IO_TYPE=LVCMOS33 ; 20 | 21 | SYSCONFIG JTAG_PORT=DISABLE SDM_PORT=PROGRAMN I2C_PORT=DISABLE SLAVE_SPI_PORT=ENABLE MCCLK_FREQ=10.23 ; 22 | 23 | ################################################# 24 | 25 | USERCODE ASCII "PIF2" ; 26 | 27 | LOCATE COMP "GSRn" SITE "136" ; # use the TDI pad as a global reset 28 | 29 | ## top bank 30 | # LOCATE COMP "FDONE" SITE "109" ; 31 | # LOCATE COMP "FINITn" SITE "110" ; 32 | LOCATE COMP "RA9" SITE "111" ; 33 | LOCATE COMP "LEDR" SITE "112" ; 34 | LOCATE COMP "LEDG" SITE "113" ; 35 | # LOCATE COMP "FPROGn" SITE "119" ; 36 | # LOCATE COMP "FJTAGn" SITE "120" ; 37 | LOCATE COMP "SDA" SITE "125" ; 38 | LOCATE COMP "SCL" SITE "126" ; 39 | # LOCATE COMP "FTMS" SITE "130" ; 40 | # LOCATE COMP "FTCK" SITE "131" ; 41 | # LOCATE COMP "FTDI" SITE "136" ; 42 | # LOCATE COMP "FTDO" SITE "137" ; 43 | LOCATE COMP "GPIO21" SITE "138" ; 44 | LOCATE COMP "GPIO26" SITE "139" ; 45 | LOCATE COMP "GPIO20" SITE "140" ; 46 | LOCATE COMP "GPIO19" SITE "141" ; 47 | LOCATE COMP "GPIO16" SITE "142" ; 48 | LOCATE COMP "GPIO13" SITE "143" ; 49 | 50 | ## right bank 51 | LOCATE COMP "RA0" SITE "73" ; 52 | LOCATE COMP "RB0" SITE "74" ; 53 | LOCATE COMP "RC0" SITE "75" ; 54 | LOCATE COMP "RA1" SITE "76" ; 55 | LOCATE COMP "RB1" SITE "77" ; 56 | LOCATE COMP "RC1" SITE "78" ; 57 | LOCATE COMP "RA2" SITE "81" ; 58 | LOCATE COMP "RB2" SITE "82" ; 59 | LOCATE COMP "RC2" SITE "83" ; 60 | LOCATE COMP "RA3" SITE "84" ; 61 | LOCATE COMP "RB3" SITE "85" ; 62 | LOCATE COMP "RC3" SITE "86" ; 63 | LOCATE COMP "RA4" SITE "87" ; 64 | LOCATE COMP "RB4" SITE "89" ; 65 | LOCATE COMP "RC4" SITE "91" ; 66 | LOCATE COMP "RA5" SITE "92" ; 67 | LOCATE COMP "RB5" SITE "93" ; 68 | LOCATE COMP "RC5" SITE "94" ; 69 | LOCATE COMP "RA6" SITE "95" ; 70 | LOCATE COMP "RB6" SITE "96" ; 71 | LOCATE COMP "RC6" SITE "97" ; 72 | LOCATE COMP "RA7" SITE "98" ; 73 | LOCATE COMP "RB7" SITE "99" ; 74 | LOCATE COMP "RC7" SITE "100" ; 75 | LOCATE COMP "RC8" SITE "103" ; 76 | LOCATE COMP "RB8" SITE "104" ; 77 | LOCATE COMP "RA8" SITE "105" ; 78 | LOCATE COMP "RC9" SITE "106" ; 79 | LOCATE COMP "RB9" SITE "107" ; 80 | 81 | ## bottom bank 82 | LOCATE COMP "BA0" SITE "38" ; 83 | LOCATE COMP "BB0" SITE "39" ; 84 | LOCATE COMP "BA1" SITE "42" ; 85 | LOCATE COMP "BB1" SITE "43" ; 86 | # LOCATE COMP "SCLK" SITE "44" ; 87 | # LOCATE COMP "MISO" SITE "45" ; 88 | LOCATE COMP "BA2" SITE "47" ; 89 | LOCATE COMP "BB2" SITE "48" ; 90 | LOCATE COMP "BB3" SITE "49" ; 91 | LOCATE COMP "BA3" SITE "50" ; 92 | LOCATE COMP "BB4" SITE "61" ; 93 | LOCATE COMP "BA4" SITE "62" ; 94 | LOCATE COMP "BB5" SITE "65" ; 95 | LOCATE COMP "BA5" SITE "67" ; 96 | LOCATE COMP "BB6" SITE "68" ; 97 | LOCATE COMP "BA6" SITE "69" ; 98 | # LOCATE COMP "CE0_FSn" SITE "70" ; 99 | # LOCATE COMP "MOSI" SITE "71" ; 100 | 101 | ## left bank 102 | LOCATE COMP "GPIO6" SITE "1" ; 103 | LOCATE COMP "GPIO12" SITE "2" ; 104 | LOCATE COMP "GPIO5" SITE "3" ; 105 | LOCATE COMP "CE1" SITE "4" ; 106 | LOCATE COMP "GPIO25" SITE "9" ; 107 | LOCATE COMP "GPIO24" SITE "11" ; 108 | 109 | LOCATE COMP "GPIO23" SITE "13" ; 110 | LOCATE COMP "GPIO22" SITE "19" ; 111 | LOCATE COMP "GPIO27" SITE "20" ; 112 | LOCATE COMP "GPIO18" SITE "23" ; 113 | 114 | LOCATE COMP "GPIO17" SITE "25" ; 115 | LOCATE COMP "GPIO15" SITE "26" ; 116 | LOCATE COMP "PiCLK" SITE "27" ; 117 | LOCATE COMP "GPIO14" SITE "32" ; 118 | 119 | 120 | IOBUF PORT "GSRn" IO_TYPE=LVCMOS33 PULLMODE=UP ; 121 | IOBUF PORT "LEDR" IO_TYPE=LVCMOS33 PULLMODE=DOWN ; 122 | IOBUF PORT "LEDG" IO_TYPE=LVCMOS33 PULLMODE=DOWN ; 123 | IOBUF PORT "SCL" IO_TYPE=LVCMOS33 PULLMODE=UP ; 124 | IOBUF PORT "SDA" IO_TYPE=LVCMOS33 PULLMODE=UP ; 125 | 126 | ## FREQUENCY NET "KLK/clkIn" 25.0 MHz HOLD_MARGIN 0.5 nS ; 127 | 128 | ## EOF ########################################## 129 | -------------------------------------------------------------------------------- /software/src/lowlevel.cpp: -------------------------------------------------------------------------------- 1 | // lowlevel.cpp ------------------------------------------------------- 2 | // 3 | // Copyright (c) 2001 to 2013 te 4 | // 5 | // Licence: Creative Commons Attribution-ShareAlike 3.0 Unported License. 6 | // http://creativecommons.org/licenses/by-sa/3.0/ 7 | //--------------------------------------------------------------------- 8 | 9 | #include 10 | 11 | #ifdef _DEBUG 12 | # include 13 | #endif 14 | 15 | #include "lowlevel.h" 16 | #include "bcm2835.h" 17 | 18 | #define XO2_I2C_CLOCK_SPEED (400 * 1000) 19 | 20 | #define MCP_FPGA_TDO (1 << 0) 21 | #define MCP_FPGA_TDI (1 << 1) 22 | #define MCP_FPGA_TCK (1 << 2) 23 | #define MCP_FPGA_TMS (1 << 3) 24 | #define MCP_FPGA_JTAGENn (1 << 4) // JTAG enable when Lo 25 | #define MCP_FPGA_PROGn (1 << 5) 26 | #define MCP_FPGA_INITn (1 << 6) 27 | #define MCP_FPGA_DONE (1 << 7) 28 | 29 | //--------------------------------------------------------------------- 30 | void TlowLevel::_setI2Caddr(int AslaveAddr) { 31 | if (Fi2cSlaveAddr != AslaveAddr) 32 | bcm2835_i2c_setSlaveAddress(AslaveAddr); 33 | Fi2cSlaveAddr = AslaveAddr; 34 | } 35 | 36 | //--------------------------------------------------------------------- 37 | bool TlowLevel::i2cWrite(int AslaveAddr, const uint8_t *pWrData, size_t AwrLen) { 38 | _setI2Caddr(AslaveAddr); 39 | FlastResult = bcm2835_i2c_write((char *)pWrData, AwrLen); 40 | return (FlastResult==BCM2835_I2C_REASON_OK); 41 | } 42 | 43 | //--------------------------------------------------------------------- 44 | bool TlowLevel::i2cRead(int AslaveAddr, uint8_t *pRdData, size_t ArdLen) { 45 | _setI2Caddr(AslaveAddr); 46 | FlastResult = bcm2835_i2c_read((char *)pRdData, ArdLen); 47 | return (FlastResult==BCM2835_I2C_REASON_OK); 48 | } 49 | 50 | //--------------------------------------------------------------------- 51 | // The max write is 1. 52 | bool TlowLevel::i2cWriteRead(int AslaveAddr, 53 | const uint8_t *pWrData, 54 | uint8_t *pRdData, size_t ArdLen) { 55 | _setI2Caddr(AslaveAddr); 56 | FlastResult = bcm2835_i2c_read_register_rs((char *)pWrData, 57 | (char *)pRdData, ArdLen); 58 | 59 | return (FlastResult==BCM2835_I2C_REASON_OK); 60 | } 61 | 62 | //--------------------------------------------------------------------- 63 | void TlowLevel::_setSpiConfig(bool Aconfig) { 64 | // TODO 65 | } 66 | 67 | //--------------------------------------------------------------------- 68 | bool TlowLevel::spiWrite(bool aConfig, const uint8_t *pWrData, size_t AwrLen) { 69 | _setSpiConfig(aConfig); 70 | FlastResult = 0; 71 | bcm2835_spi_writenb((char *)pWrData, AwrLen); 72 | return true; 73 | } 74 | 75 | //--------------------------------------------------------------------- 76 | bool TlowLevel::spiRead(bool aConfig, uint8_t *pRdData, size_t ArdLen) { 77 | _setSpiConfig(aConfig); 78 | FlastResult = 0; 79 | bcm2835_spi_transfern((char *)pRdData, ArdLen); 80 | return true; 81 | } 82 | 83 | //--------------------------------------------------------------------- 84 | bool TlowLevel::spiWriteRead(bool aConfig, 85 | const uint8_t *pWrData, size_t AwrLen, 86 | uint8_t *pRdData, size_t ArdLen) { 87 | _setSpiConfig(aConfig); 88 | FlastResult = 0; 89 | 90 | uint8_t *buff = new uint8_t[AwrLen + ArdLen]; 91 | memcpy(buff, pWrData, AwrLen); 92 | memcpy(buff+AwrLen, pRdData, ArdLen); 93 | bcm2835_spi_transfern((char *)buff, AwrLen + ArdLen); 94 | memcpy(pRdData, buff+AwrLen, ArdLen); 95 | delete[] buff; 96 | return true; 97 | } 98 | 99 | //--------------------------------------------------------------------- 100 | TlowLevel::TlowLevel() : Fi2cSlaveAddr(~I2C_APP_ADDR) { 101 | int res = bcm2835_init(); 102 | Finitialised = (res == 1); 103 | 104 | if (Finitialised) { 105 | // i2c initialise 106 | //bcm2835_set_debug(10); 107 | bcm2835_i2c_begin(); 108 | bcm2835_i2c_set_baudrate(XO2_I2C_CLOCK_SPEED); 109 | 110 | // MCP23008 bits 111 | _setI2Caddr(MCP23008_ADDR); 112 | TllWrBuf oBuf; 113 | oBuf.clear().byte(6).byte(0xff); // all pullups 114 | i2cWrite(MCP23008_ADDR, oBuf.data(), oBuf.length()); 115 | oBuf.clear().byte(9).byte(0xf7); // output reg 116 | i2cWrite(MCP23008_ADDR, oBuf.data(), oBuf.length()); 117 | oBuf.clear().byte(0).byte(0xe1); // set inputs 118 | i2cWrite(MCP23008_ADDR, oBuf.data(), oBuf.length()); 119 | 120 | _setI2Caddr(I2C_APP_ADDR); 121 | 122 | // spi initialise 123 | bcm2835_spi_begin(); 124 | bcm2835_spi_setBitOrder(BCM2835_SPI_BIT_ORDER_MSBFIRST); // default 125 | bcm2835_spi_setDataMode(BCM2835_SPI_MODE0); // default 126 | // bcm2835_spi_setClockDivider(BCM2835_SPI_CLOCK_DIVIDER_65536); // default 127 | bcm2835_spi_setClockDivider(BCM2835_SPI_CLOCK_DIVIDER_32); // 8MHz 128 | bcm2835_spi_chipSelect(BCM2835_SPI_CS0); // default 129 | bcm2835_spi_setChipSelectPolarity(BCM2835_SPI_CS0, LOW); // default 130 | } 131 | } 132 | 133 | //--------------------------------------------------------------------- 134 | TlowLevel::~TlowLevel() { 135 | if (Finitialised) { 136 | bcm2835_spi_end(); 137 | bcm2835_i2c_end(); 138 | bcm2835_close(); 139 | } 140 | Finitialised = false; 141 | } 142 | 143 | // EOF ---------------------------------------------------------------- 144 | /* 145 | // Send a byte to the slave and simultaneously read a byte back from the slave 146 | // If you tie MISO to MOSI, you should read back what was sent 147 | uint8_t data = bcm2835_spi_transfer(0x23); 148 | printf("Read from SPI: %02X\n", data); 149 | 150 | */ 151 | -------------------------------------------------------------------------------- /software/src/pifload.cpp: -------------------------------------------------------------------------------- 1 | //--------------------------------------------------------------------- 2 | // pifload.cpp 3 | 4 | using namespace std; 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include "pifwrap.h" 13 | 14 | extern const int g_iDataSize; 15 | extern const unsigned char g_pucDataArray[]; 16 | 17 | #define CFG_PAGE_SIZE 16 18 | #define UFM_PAGE_SIZE 16 19 | 20 | static const int MICROSEC = 1000; // nanosecs 21 | static const int MILLISEC = 1000 * MICROSEC; // nanosecs 22 | 23 | //--------------------------------------------------------------------- 24 | static bool showDeviceID(pifHandle h) { 25 | uint32_t v = 0x12345678; 26 | bool res = pifGetDeviceIdCode(h, &v); 27 | printf("result=%d, ID code=%08x\n", res, v); 28 | return res; 29 | } 30 | 31 | //--------------------------------------------------------------------- 32 | static bool showTraceID(pifHandle h) { 33 | uint8_t buff[8] = {1,2,3,4,5,6,7,8}; 34 | bool res = pifGetTraceId(h, buff); 35 | printf("result=%d, Trace ID code= ", res); 36 | for (unsigned i=0; i> 6) & 1; 58 | } 59 | 60 | //--------------------------------------------------------------------- 61 | static void showCfgStatus(pifHandle h) { 62 | uint32_t status=0; 63 | pifGetStatusReg(h, &status); 64 | 65 | /*printf("\n----------------------------");*/ 66 | int init = INITn(h); 67 | printf("*** status = %8x, INITn = %d", status, init); 68 | 69 | string fcStatus; 70 | uint32_t errCode = (status >> 23) & 7; 71 | switch (errCode) { 72 | case 0: fcStatus = "No Error"; break; 73 | case 1: fcStatus = "ID ERR"; break; 74 | case 2: fcStatus = "CMD ERR"; break; 75 | case 3: fcStatus = "CRC ERR"; break; 76 | case 4: fcStatus = "Preamble ERR"; break; 77 | case 5: fcStatus = "Abort ERR"; break; 78 | case 6: fcStatus = "Overflow ERR"; break; 79 | case 7: fcStatus = "SDM EOF"; break; 80 | } 81 | printf(" Done=%d, CfgEna=%d, Busy=%d, Fail=%d, FlashCheck=%s\n", 82 | ((status >> 8) & 1), 83 | ((status >> 9) & 1), 84 | ((status >> 12) & 1), 85 | ((status >> 13) & 1), fcStatus.c_str()); 86 | } 87 | 88 | //--------------------------------------------------------------------- 89 | static int flipNybble(int nyb) { 90 | int x = nyb & 0xf; 91 | int v = ((x & (1<<0)) << 3) | 92 | ((x & (1<<1)) << 1) | 93 | ((x & (1<<2)) >> 1) | 94 | ((x & (1<<3)) >> 3); 95 | return v; 96 | } 97 | 98 | //--------------------------------------------------------------------- 99 | static uint8_t flipByte(int x) { 100 | int lo = x & 0xf, hi = (x>>4), v = 0; 101 | v = flipNybble(hi) | (flipNybble(lo) << 4); 102 | return (uint8_t)v; 103 | } 104 | 105 | //--------------------------------------------------------------------- 106 | static void configureXO2(pifHandle h) { 107 | int cfg_page_count = (g_iDataSize-1) / (CFG_PAGE_SIZE+1); 108 | cfg_page_count = 9212; 109 | 110 | printf("\n----------------------------\n"); 111 | 112 | pifWaitUntilNotBusy(h, -1); 113 | 114 | pifDisableCfgInterface(h); 115 | showCfgStatus(h); 116 | pifEnableCfgInterfaceOffline(h); 117 | 118 | showCfgStatus(h); 119 | printf("erasing configuration memory..\n"); 120 | pifEraseCfg(h); 121 | printf("erased..\n"); 122 | 123 | pifInitCfgAddr(h); 124 | showCfgStatus(h); 125 | printf("programming configuration memory..\n"); // up to 2.2 secs in a -7000 126 | 127 | uint8_t frameData[CFG_PAGE_SIZE]; 128 | for (int pageNum=0; pageNum'0'); 28 | begin 29 | 30 | process (Clk) begin 31 | if rising_edge(Clk) then 32 | if CE='1' then 33 | if LoadN='0' then 34 | Ctr <= '0' & InitialVal; 35 | else 36 | Ctr <= Ctr -1; 37 | end if; 38 | end if; 39 | end if; 40 | end process; 41 | 42 | zero <= Ctr(BITS) = '1'; 43 | end rtl; 44 | 45 | ----------------------------------------------------------------------- 46 | library ieee; use ieee.std_logic_1164.all; 47 | use ieee.numeric_std.all; 48 | -- use ieee.math_real.all; 49 | library machxo2; use machxo2.components.all; 50 | 51 | entity pif_flasher is port ( red, green, xclk : out std_logic ); 52 | end pif_flasher; 53 | 54 | architecture rtl of pif_flasher is 55 | ----------------------------------------------- 56 | component osch is 57 | -- synthesis translate_off 58 | generic (nom_freq: string := "2.08"); 59 | -- synthesis translate_on 60 | port ( stdby :in std_logic; 61 | osc :out std_logic; 62 | sedstdby :out std_logic ); 63 | end component osch; 64 | ----------------------------------------------- 65 | component DownCounter is generic (BITS : natural := 10); 66 | port ( 67 | Clk : in std_logic; 68 | InitialVal : in unsigned(BITS-1 downto 0); 69 | LoadN, 70 | CE : in std_logic; 71 | zero : out boolean ); 72 | end component DownCounter; 73 | ----------------------------------------------- 74 | function to_sl(b: boolean) return std_logic is 75 | begin 76 | if b then return '1'; else return '0'; end if; 77 | end to_sl; 78 | ----------------------------------------------- 79 | -- calculate the number of bits required to represent a given value 80 | function numBits(arg : natural) return natural is 81 | begin 82 | case arg is 83 | when 1 | 0 => 84 | return 1; 85 | when others => 86 | return 1 + numBits(arg/2); 87 | end case; 88 | end; 89 | --------------------------------------------------------------------- 90 | 91 | constant OSC_RATE : natural := (26600 * 1000); 92 | constant OSC_STR : string := "26.60"; 93 | constant TICK_RATE: integer := 150; 94 | 95 | attribute nom_freq : string; 96 | attribute nom_freq of oscinst0 : label is OSC_STR; 97 | 98 | signal osc : std_logic; 99 | 100 | -- each slot containing 2**B ticks 101 | constant B : integer := 5; 102 | signal Tick : boolean; 103 | 104 | -- the ramping LED signal 105 | signal LedOn : boolean; 106 | 107 | -- red/green outputs 108 | signal R,G : std_logic := '0'; 109 | 110 | -- phase accumulator for the PWM 111 | signal Accum : unsigned(B downto 0) := (others=>'0'); 112 | 113 | -- saw-tooth incrementing Phase Delta register 114 | signal DeltaReg : unsigned(B+1 downto 0) := (others=>'0'); 115 | 116 | -- low bits of DeltaReg 117 | signal Delta : unsigned(B-1 downto 0); 118 | 119 | -- high bits of DeltaReg 120 | signal LedPhase : unsigned(1 downto 0); 121 | 122 | begin 123 | ------------------------------------------------------------- 124 | -- instantiate the internal oscillator 125 | OSCInst0: osch 126 | -- synthesis translate_off 127 | generic map ( nom_freq => OSC_STR ) 128 | -- synthesis translate_on 129 | port map ( stdby => '0', -- could use a standby signal 130 | osc => osc, 131 | sedstdby => open ); -- for simulation, use stdby_sed sig 132 | 133 | ------------------------------------------------------------- 134 | -- generate the Tick clock 135 | TBLOCK: block 136 | -- divide down from 2MHz to approx 150Hz 137 | constant FREQ_DIV: natural := OSC_RATE/TICK_RATE; 138 | 139 | constant TICK_LEN: natural := FREQ_DIV 140 | -- synthesis translate_off 141 | - FREQ_DIV + 8 -- make the simulation reasonable! 142 | -- synthesis translate_on 143 | ; 144 | constant CLEN: natural := numBits(TICK_LEN); 145 | constant DIV : unsigned(CLEN-1 downto 0) := to_unsigned(TICK_LEN, CLEN); 146 | 147 | signal LoadN: std_logic; 148 | begin 149 | LoadN <= '0' when Tick else '1'; 150 | TK: DownCounter generic map ( BITS => CLEN ) 151 | port map ( Clk => osc, 152 | InitialVal => DIV, 153 | LoadN => LoadN, 154 | CE => '1', 155 | zero => Tick ); 156 | end block TBLOCK; 157 | 158 | ------------------------------------------------------------- 159 | -- increment the Delta register and the 0.1.2.3 phase counter 160 | Delta <= DeltaReg(Delta'range); 161 | LedPhase <= DeltaReg(DeltaReg'high downto DeltaReg'high-1); 162 | 163 | process (osc) 164 | begin 165 | if rising_edge(osc) then 166 | if Tick then 167 | DeltaReg <= DeltaReg+1; 168 | end if; 169 | end if; 170 | end process; 171 | 172 | -- generate the LED PWM signal 173 | process (osc) 174 | variable Acc, Delt: unsigned(Accum'range); 175 | begin 176 | if rising_edge(osc) then 177 | if Tick then 178 | Accum <= (others=>'0'); 179 | else 180 | Acc := '0' & Accum(B-1 downto 0); -- clear overflow to zero 181 | Delt:= '0' & Delta; -- bit-extend with zero 182 | Accum <= Acc + Delt; 183 | end if; 184 | 185 | LedOn <= (Accum(B) = '1'); -- overflow drives LED 186 | 187 | R <= not to_sl(((LedPhase=0) and LedOn) or ((LedPhase=1) and not LedOn)); 188 | G <= not to_sl(((LedPhase=2) and LedOn) or ((LedPhase=3) and not LedOn)); 189 | end if; 190 | end process; 191 | 192 | red <= R; 193 | green <= G; 194 | xclk <= osc; 195 | 196 | end rtl; 197 | -- EOF piffla.vhd ----------------------------------------------------- 198 | -------------------------------------------------------------------------------- /firmware/common/pifdefs.vhd: -------------------------------------------------------------------------------- 1 | ----------------------------------------------------------------------- 2 | -- pifdefs.vhd Bugblat pif definitions 3 | -- 4 | -- Initial entry: 05-Jan-12 te 5 | -- Copyright (c) 2001 to 2013 te 6 | -- 7 | ----------------------------------------------------------------------- 8 | library ieee; use ieee.std_logic_1164.all; 9 | use ieee.numeric_std.all; 10 | library work; use work.pifcfg.all; 11 | 12 | package defs is 13 | 14 | -- save lots of typing 15 | subtype slv2 is std_logic_vector( 1 downto 0); 16 | subtype slv3 is std_logic_vector( 2 downto 0); 17 | subtype slv4 is std_logic_vector( 3 downto 0); 18 | subtype slv5 is std_logic_vector( 4 downto 0); 19 | subtype slv6 is std_logic_vector( 5 downto 0); 20 | subtype slv7 is std_logic_vector( 6 downto 0); 21 | subtype slv8 is std_logic_vector( 7 downto 0); 22 | subtype slv16 is std_logic_vector(15 downto 0); 23 | subtype slv32 is std_logic_vector(31 downto 0); 24 | 25 | ------------------------------------------------------------- 26 | -- these constants are defined in outer 'pifcfg' files 27 | constant ID : std_logic_vector(7 downto 0) := PIF_ID; 28 | constant DEVICE_DENSITY : string := XO2_DENSITY; 29 | 30 | -- I2C interface -------------------------------------------- 31 | 32 | constant A_ADDR : slv2 := "00"; 33 | constant D_ADDR : slv2 := "01"; 34 | 35 | constant I2C_TYPE_BITS : integer := 2; 36 | constant I2C_DATA_BITS : integer := 6; 37 | 38 | subtype TincomingTypeRange is integer range 7 downto I2C_DATA_BITS; 39 | subtype TincomingDataRange is integer range (I2C_DATA_BITS-1) downto 0; 40 | 41 | subtype TwrData is std_logic_vector(TincomingDataRange); 42 | subtype TbyteType is std_logic_vector(TincomingTypeRange); 43 | 44 | constant XA_BITS : integer := 4; -- 16 registers 45 | constant XSUBA_BITS : integer := 7; -- 128 sub-addresses 46 | constant XSUBA_MAX : integer := 2**XSUBA_BITS -1; 47 | 48 | subtype TXARange is integer range XA_BITS-1 downto 0; 49 | subtype TXA is integer range 0 to 2**XA_BITS -1; 50 | subtype TXSubA is integer range 0 to XSUBA_MAX; 51 | 52 | subtype TXDRange is integer range 0 to (2**I2C_DATA_BITS) -1; 53 | 54 | ------------------------------------------------------------- 55 | type XIrec is record -- write data for regs 56 | PWr : boolean; -- registered single-clock write strobe 57 | PRWA : TXA; -- registered incoming addr bus 58 | PRdFinished : boolean; -- registered in clock PRDn goes off 59 | PRdSubA : TXSubA; -- read sub-address 60 | PD : TwrData; -- registered incoming data bus 61 | end record XIrec; 62 | 63 | ------------------------------------------------------------- 64 | -- ID register, read-only 65 | constant R_ID : TXA := 0; 66 | 67 | -- ID subregisters 68 | -- 0 ID BX4/8/16 = G/L/A 69 | -- 1 Scratch 70 | -- 2 Misc plus 30h -> 0/1/2/3 71 | -- 3..31 ID letter abcdefghij... 72 | -- 73 | constant R_ID_NUM_SUBS : integer := 32; 74 | constant R_ID_ID : integer := 0; 75 | constant R_ID_SCRATCH : integer := 1; 76 | constant R_ID_MISC : integer := 2; 77 | 78 | -- Scratch register, write here, read via R_ID, subaddr 1 79 | constant W_SCRATCH_REG : TXA := 1; 80 | 81 | -- Misc register, write here, read via R_ID, subaddr 2 82 | -- one of the examples uses this register to control the LEDs 83 | constant W_MISC_REG : TXA := 2; 84 | subtype TMisc is integer range 0 to 2; 85 | constant LED_ALTERNATING : TMisc := 0; 86 | constant LED_SYNC : TMisc := 1; 87 | constant LED_OFF : TMisc := 2; 88 | 89 | ------------------------------------------------------------- 90 | -- intercept calls to conv_integer and to_integer 91 | function ToInteger(arg: std_logic_vector) return integer; 92 | function ToInteger(arg: unsigned) return integer; 93 | function ToInteger(arg: signed) return integer; 94 | 95 | -- convert boolean to std_logic ( t->1, f->0 ) 96 | function to_sl(b: boolean) return std_logic; 97 | 98 | -- convert to std_logic vector 99 | function n2slv (n,l: natural ) return std_logic_vector; 100 | 101 | end package defs; 102 | 103 | --============================================================= 104 | package body defs is 105 | ------------------------------------------------------------- 106 | -- put the to_integer/conv_integer resolution in one place 107 | function ToInteger(arg: unsigned) return integer is 108 | variable x: unsigned(arg'range); 109 | variable n: integer; 110 | begin 111 | x := arg; 112 | -- synthesis translate_off 113 | for i in x'range loop 114 | if x(i)/='1' then -- resolve the 'undefined' signals 115 | x(i) := '0'; 116 | end if; 117 | end loop; 118 | -- synthesis translate_on 119 | n := to_integer(x); 120 | return n; 121 | end; 122 | ------------------------------------------------------------- 123 | function ToInteger(arg: signed) return integer is 124 | variable x: signed(arg'range); 125 | variable n: integer; 126 | begin 127 | x := arg; 128 | -- synthesis translate_off 129 | for i in x'range loop 130 | if x(i)/='1' then 131 | x(i) := '0'; 132 | end if; 133 | end loop; 134 | -- synthesis translate_on 135 | n := to_integer(x); 136 | return n; 137 | end; 138 | ------------------------------------------------------------- 139 | function ToInteger(arg: std_logic_vector) return integer is 140 | variable x: unsigned(arg'range); 141 | variable n: integer; 142 | begin 143 | x := unsigned(arg); 144 | -- synthesis translate_off 145 | for i in x'range loop 146 | if x(i)/='1' then -- resolve the 'undefined' signals 147 | x(i) := '0'; 148 | end if; 149 | end loop; 150 | -- synthesis translate_on 151 | n := to_integer(x); 152 | return n; 153 | end; 154 | ------------------------------------------------------------- 155 | function ToInteger(arg: std_ulogic_vector) return integer is 156 | variable x: std_logic_vector(arg'range); 157 | begin 158 | x := std_logic_vector(arg); 159 | return ToInteger(x); 160 | end; 161 | ------------------------------------------------------------- 162 | function to_sl(b: boolean) return std_logic is 163 | variable s: std_logic; 164 | begin 165 | if b then s :='1'; else s :='0'; end if; 166 | return s; 167 | end to_sl; 168 | ------------------------------------------------------------- 169 | function n2slv ( N,L: natural ) return std_logic_vector is 170 | variable vec: std_logic_vector(L-1 downto 0); 171 | variable Nx : natural; 172 | begin 173 | Nx := N rem 2**L; 174 | vec := std_logic_vector(to_unsigned(Nx,L)); 175 | return vec; 176 | end; 177 | 178 | end package body defs; 179 | 180 | -- EOF pifdefs.vhd -------------------------------------------- 181 | -------------------------------------------------------------------------------- /software/pifload.py: -------------------------------------------------------------------------------- 1 | #---------------------------------------------------------------------- 2 | # Name: pifload.py 3 | # Purpose: load a configuration into a pif board via the hidapi DLL/SO 4 | # 5 | # Author: Tim 6 | # 7 | # Created: 01/07/2013 8 | # Copyright: (c) Tim 2013 9 | # Licence: Creative Commons Attribution-ShareAlike 3.0 Unported License. 10 | #---------------------------------------------------------------------- 11 | #!/usr/bin/env python 12 | 13 | import sys, ctypes, pifglobs 14 | from ctypes import * 15 | from pifglobs import * 16 | 17 | # import rpdb2 18 | # rpdb2.start_embedded_debugger('pw') 19 | 20 | traceFile = None 21 | DEVICE_NAME_TAG = 'NOTE DEVICE NAME:' 22 | PACKAGE_TAG = 'TQFP144' 23 | 24 | ##--------------------------------------------------------- 25 | def showCfgStatus(handle): 26 | ## tbd 27 | return True 28 | 29 | ##--------------------------------------------------------- 30 | def print4(v): 31 | x = list(v.raw) 32 | s = '' 33 | for i in range(0, 4): 34 | if i==0: 35 | s += '' 36 | else: 37 | s+= '.' 38 | s += ('%02X' % ord(x[i])) 39 | print(s) 40 | 41 | ##--------------------------------------------------------- 42 | def showDeviceID(handle): 43 | 44 | dw = c_ulong(0xdeadbeef) 45 | res = pifglobs.pif.pifGetDeviceIdCode(handle, byref(dw)) 46 | if (res == 0): 47 | print("\nread ID code failed\n") 48 | return "failed" 49 | 50 | deviceID = dw.value 51 | print('XO2 Device ID: %08x' % deviceID) , 52 | 53 | s = UNRECOGNIZED 54 | ok = (deviceID & 0xffff8fff) == (0x012ba043 & 0xffff8fff) 55 | model = (deviceID >> 12) & 7; 56 | 57 | if model == 0 : 58 | s = "XO2-256HC" 59 | elif model == 1 : 60 | s = "XO2-640HC" 61 | elif model == 2 : 62 | s = "XO2-1200HC" 63 | elif model == 3 : 64 | s = "XO2-2000HC" 65 | elif model == 4 : 66 | s = "XO2-4000HC" 67 | elif model == 5 : 68 | s = "XO2-7000HC" 69 | else: 70 | s = UNRECOGNIZED 71 | ok = false; 72 | 73 | if ok == True: 74 | print(" - device is an " + s) 75 | else: 76 | print(" - unrecognised ID!") 77 | 78 | return s; 79 | 80 | ##--------------------------------------------------------- 81 | def pageCount(model): 82 | if model == "XO2-1200HC": 83 | return CFG_PAGE_COUNT_1200 84 | elif model == "XO2-2000HC": 85 | return CFG_PAGE_COUNT_2000 86 | elif model == "XO2-4000HC": 87 | return CFG_PAGE_COUNT_4000 88 | elif model == "XO2-7000HC": 89 | return CFG_PAGE_COUNT_7000 90 | else: 91 | return 0 92 | 93 | ##--------------------------------------------------------- 94 | ## one byte programmable, seven bytes are die ID 95 | def showTraceID(handle): 96 | buff = create_string_buffer(8) 97 | res = pifglobs.pif.pifGetTraceId(handle, buff) 98 | 99 | s = "XO2 Trace ID : " 100 | tid = list(buff.raw) 101 | for i in range(0, 8): 102 | if i==0: 103 | s += '' 104 | elif i==4: 105 | s += '_' 106 | else: 107 | s+= '.' 108 | s += ('%02X' % ord(tid[i])) 109 | print(s) 110 | return (res >= 0) 111 | 112 | ##--------------------------------------------------------- 113 | ## EN on - read from CFG Flash 114 | ## EN off - read from SRAM 115 | def showUsercode(handle): 116 | buff = create_string_buffer(4) 117 | res = pifglobs.pif.pifEnableCfgInterfaceTransparent(handle) 118 | res = pifglobs.pif.pifGetUsercode(handle, buff) 119 | res = pifglobs.pif.pifDisableCfgInterface(handle) 120 | print("XO2 usercode from Flash: ") , 121 | print4(buff) 122 | 123 | res = pifglobs.pif.pifGetUsercode(handle, buff) 124 | print("XO2 usercode from SRAM : ") , 125 | print4(buff) 126 | 127 | ##--------------------------------------------------------- 128 | def processLine(line): 129 | global traceFile 130 | l = line.strip('\n') 131 | n = len(l) 132 | v = [] 133 | for i in range(0, CFG_PAGE_SIZE): 134 | s = line[(i*8):(i*8+8)] 135 | x = int(s, 2) 136 | v.append(x) 137 | if traceFile: 138 | traceFile.write('0x%02x,' % x) 139 | if (i % 4) == 3: 140 | traceFile.write(' ') 141 | if traceFile: 142 | traceFile.write('\n') 143 | return v 144 | 145 | ##--------------------------------------------------------- 146 | def readJedecFile(fname, dev): 147 | global traceFile 148 | print('JEDEC file is ' + fname) 149 | 150 | data = [] 151 | correctDevice = False 152 | jedecID = None 153 | f = open(fname, 'r') 154 | print('starting to read JEDEC file ') , 155 | lnum = 0; 156 | state = 'initial' 157 | 158 | for line in f: 159 | lnum += 1 160 | if (lnum % 250) == 0: 161 | print('.') , 162 | 163 | if len(line) < 1: 164 | continue 165 | 166 | # check JEDEC for, e.g., NOTE DEVICE NAME: LCMXO2-7000HC-4TQFP144* 167 | if DEVICE_NAME_TAG in line: 168 | jedecID = line.strip() 169 | correctDevice = (dev in line) and (PACKAGE_TAG in line) 170 | if not correctDevice: 171 | break 172 | 173 | c0 = line[0] 174 | valid = (c0=='0') or (c0=='1') 175 | if state == 'initial': 176 | if valid: 177 | print('\nfirst configuration data line: %d' % lnum) 178 | state = 'inData' 179 | v = processLine(line) 180 | data.append(v) 181 | elif state == 'inData': 182 | if valid: 183 | v = processLine(line) 184 | data.append(v) 185 | else: 186 | print('\nlast configuration data line: %d' % (lnum-1)) 187 | state = 'finished' 188 | break 189 | 190 | f.close() 191 | if traceFile: 192 | traceFile.close() 193 | 194 | if not correctDevice: 195 | print('\nJEDEC file does not match FPGA') 196 | print('\n FPGA is ' + dev) 197 | if jedecID: 198 | print('\n JEDEC identifies as "' + jedecID + '"') 199 | return [] 200 | 201 | print('%d frames' % len(data)) 202 | print('finished reading JEDEC file') 203 | return data 204 | 205 | ##--------------------------------------------------------- 206 | def configure(handle, fname, dev): 207 | jedecData = readJedecFile(fname, dev) 208 | 209 | if len(jedecData) == 0: 210 | return 211 | 212 | pifglobs.pif.pifWaitUntilNotBusy(handle, -1) 213 | showCfgStatus(handle) 214 | 215 | res = pifglobs.pif.pifEnableCfgInterfaceOffline(handle) 216 | showCfgStatus(handle) 217 | 218 | print('erasing configuration flash ... ') , 219 | res = pifglobs.pif.pifInitCfgAddr(handle) 220 | res = pifglobs.pif.pifEraseCfg(handle) 221 | showCfgStatus(handle) 222 | print('erased') 223 | 224 | res = pifglobs.pif.pifInitCfgAddr(handle) 225 | 226 | print('programming configuration flash ... '), 227 | frameData = create_string_buffer(CFG_PAGE_SIZE) 228 | numPages = len(jedecData); 229 | for pageNum in range(0, numPages) : 230 | frame = jedecData[pageNum] 231 | for i in range(0, CFG_PAGE_SIZE) : 232 | frameData[i] = chr(frame[i]) 233 | res = pifglobs.pif.pifProgCfgPage(handle, frameData) 234 | if (pageNum % 25) == 0: 235 | print('.') , 236 | 237 | print('programmed \ntransferring ... ') 238 | 239 | res = pifglobs.pif.pifProgDone(handle) 240 | res = pifglobs.pif.pifRefresh(handle) 241 | res = pifglobs.pif.pifDisableCfgInterface(handle) 242 | showCfgStatus(handle) 243 | print('configuration finished.') 244 | 245 | ##--------------------------------------------------------- 246 | def main(): 247 | print('====================hello==========================') 248 | handle = None 249 | jedecFile = None 250 | try: 251 | try: 252 | jedecFile = sys.argv[1] 253 | except: 254 | print 'pifload.py ' 255 | sys.exit(2) 256 | 257 | print('Configuration file is ' + jedecFile) 258 | 259 | pifglobs.pif = ctypes.CDLL("libpif.so") 260 | 261 | strBuf = create_string_buffer(1000) 262 | rv = pifglobs.pif.pifVersion(strBuf, sizeof(strBuf)) 263 | print('Using pif library version: %s\n' % repr(strBuf.value)) 264 | 265 | handle = c_int(pifglobs.pif.pifInit()) 266 | dev = showDeviceID(handle) 267 | 268 | if dev != UNRECOGNIZED: 269 | showTraceID(handle) 270 | showUsercode(handle) 271 | if jedecFile: 272 | configure(handle, jedecFile, dev) 273 | 274 | except: 275 | e = sys.exc_info()[0] 276 | print('\nException caught %s\n' % e) 277 | 278 | print('\n==================== bye ==========================') 279 | 280 | ##--------------------------------------------------------- 281 | if __name__ == '__main__': 282 | main() 283 | 284 | # EOF ----------------------------------------------------------------- 285 | -------------------------------------------------------------------------------- /firmware/common/efb.vhd: -------------------------------------------------------------------------------- 1 | -- VHDL netlist generated by SCUBA Diamond_1.4_Production (87) 2 | -- Module Version: 1.0 3 | 4 | -- Tue May 08 13:20:29 2012 5 | -- 6 | -- Copyright (c) 2012 te 7 | -- 8 | ----------------------------------------------------------------------- 9 | 10 | library ieee; use ieee.std_logic_1164.all; 11 | library work; use work.defs.all; 12 | library MACHXO2; use MACHXO2.components.all; 13 | 14 | entity efbx is 15 | port ( 16 | wb_clk_i : in std_logic; 17 | wb_rst_i : in std_logic; 18 | wb_cyc_i : in std_logic; 19 | wb_stb_i : in std_logic; 20 | wb_we_i : in std_logic; 21 | wb_adr_i : in std_logic_vector(7 downto 0); 22 | wb_dat_i : in std_logic_vector(7 downto 0); 23 | wb_dat_o : out std_logic_vector(7 downto 0); 24 | wb_ack_o : out std_logic; 25 | i2c1_scl : inout std_logic; 26 | i2c1_sda : inout std_logic; 27 | i2c1_irqo : out std_logic ); 28 | end efbx; 29 | 30 | architecture struct of efbx is 31 | 32 | signal scuba_vhi, scuba_vlo, 33 | i2c1_sdao, i2c1_sdaoen, 34 | i2c1_sclo, i2c1_scloen, 35 | i2c1_sdai, i2c1_scli : std_logic; 36 | 37 | ------------------------------------------------- 38 | component VHI 39 | port (Z: out std_logic); 40 | end component; 41 | 42 | ------------------------------------------------- 43 | component VLO 44 | port (Z: out std_logic); 45 | end component; 46 | 47 | ------------------------------------------------- 48 | component BB 49 | port (I: in std_logic; T: in std_logic; O: out std_logic; 50 | B: inout std_logic); 51 | end component; 52 | 53 | begin 54 | 55 | scuba_vhi_inst: VHI port map (Z=>scuba_vhi); 56 | scuba_vlo_inst: VLO port map (Z=>scuba_vlo); 57 | 58 | BB1_sda: BB port map (I=>i2c1_sdao, T=>i2c1_sdaoen, O=>i2c1_sdai, 59 | B=>i2c1_sda); 60 | 61 | BB1_scl: BB port map (I=>i2c1_sclo, T=>i2c1_scloen, O=>i2c1_scli, 62 | B=>i2c1_scl); 63 | 64 | EFBInst_0: EFB 65 | generic map ( 66 | EFB_I2C1 => "ENABLED", 67 | EFB_I2C2 => "DISABLED", 68 | EFB_SPI => "DISABLED", 69 | EFB_TC => "ENABLED", 70 | EFB_TC_PORTMODE => "WB", 71 | EFB_UFM => "ENABLED", 72 | EFB_WB_CLK_FREQ => "27.0", 73 | 74 | UFM_INIT_FILE_FORMAT => "HEX", 75 | UFM_INIT_FILE_NAME => "NONE", 76 | UFM_INIT_ALL_ZEROS => "ENABLED", 77 | UFM_INIT_START_PAGE => 0, 78 | UFM_INIT_PAGES => 0, 79 | DEV_DENSITY => DEVICE_DENSITY, -- in defs 80 | 81 | GSR => "ENABLED", 82 | TC_ICAPTURE => "DISABLED", 83 | TC_OVERFLOW => "DISABLED", 84 | TC_ICR_INT => "OFF", 85 | TC_OCR_INT => "OFF", 86 | TC_OV_INT => "OFF", 87 | TC_TOP_SEL => "ON", 88 | TC_RESETN => "ENABLED", -- used in debug mode only 89 | TC_OC_MODE => "WAVE_GENERATOR", 90 | TC_OCR_SET => 27, -- 28-1 91 | TC_TOP_SET => 65, -- 66-1..... 92 | TC_CCLK_SEL => 1, 93 | TC_MODE => "FASTPWM", 94 | TC_SCLK_SEL => "PCLOCK", 95 | 96 | SPI_WAKEUP => "DISABLED", 97 | SPI_INTR_RXOVR => "DISABLED", 98 | SPI_INTR_TXOVR => "DISABLED", 99 | SPI_INTR_RXRDY => "DISABLED", 100 | SPI_INTR_TXRDY => "DISABLED", 101 | SPI_SLAVE_HANDSHAKE => "DISABLED", 102 | SPI_PHASE_ADJ => "DISABLED", 103 | SPI_CLK_INV => "DISABLED", 104 | SPI_LSB_FIRST => "DISABLED", 105 | SPI_CLK_DIVIDER => 1, 106 | SPI_MODE => "MASTER", 107 | 108 | I2C2_WAKEUP => "DISABLED", 109 | I2C2_GEN_CALL => "DISABLED", 110 | I2C2_CLK_DIVIDER => 1, 111 | I2C2_BUS_PERF => "100kHz", 112 | I2C2_SLAVE_ADDR => "0b0011001", 113 | I2C2_ADDRESSING => "7BIT", 114 | 115 | I2C1_WAKEUP => "DISABLED", 116 | I2C1_GEN_CALL => "DISABLED", 117 | I2C1_CLK_DIVIDER => 17, 118 | I2C1_BUS_PERF => "400kHz", 119 | I2C1_SLAVE_ADDR => "0b1000001", 120 | I2C1_ADDRESSING => "7BIT" ) 121 | port map ( 122 | WBCLKI => wb_clk_i, 123 | WBRSTI => wb_rst_i, 124 | WBCYCI => wb_cyc_i, 125 | WBSTBI => wb_stb_i, 126 | WBWEI => wb_we_i, 127 | WBADRI7 => wb_adr_i(7), 128 | WBADRI6 => wb_adr_i(6), 129 | WBADRI5 => wb_adr_i(5), 130 | WBADRI4 => wb_adr_i(4), 131 | WBADRI3 => wb_adr_i(3), 132 | WBADRI2 => wb_adr_i(2), 133 | WBADRI1 => wb_adr_i(1), 134 | WBADRI0 => wb_adr_i(0), 135 | WBDATI7 => wb_dat_i(7), 136 | WBDATI6 => wb_dat_i(6), 137 | WBDATI5 => wb_dat_i(5), 138 | WBDATI4 => wb_dat_i(4), 139 | WBDATI3 => wb_dat_i(3), 140 | WBDATI2 => wb_dat_i(2), 141 | WBDATI1 => wb_dat_i(1), 142 | WBDATI0 => wb_dat_i(0), 143 | PLL0DATI7 => scuba_vlo, 144 | PLL0DATI6 => scuba_vlo, 145 | PLL0DATI5 => scuba_vlo, 146 | PLL0DATI4 => scuba_vlo, 147 | PLL0DATI3 => scuba_vlo, 148 | PLL0DATI2 => scuba_vlo, 149 | PLL0DATI1 => scuba_vlo, 150 | PLL0DATI0 => scuba_vlo, 151 | PLL0ACKI => scuba_vlo, 152 | PLL1DATI7 => scuba_vlo, 153 | PLL1DATI6 => scuba_vlo, 154 | PLL1DATI5 => scuba_vlo, 155 | PLL1DATI4 => scuba_vlo, 156 | PLL1DATI3 => scuba_vlo, 157 | PLL1DATI2 => scuba_vlo, 158 | PLL1DATI1 => scuba_vlo, 159 | PLL1DATI0 => scuba_vlo, 160 | PLL1ACKI => scuba_vlo, 161 | I2C1SCLI => i2c1_scli, 162 | I2C1SDAI => i2c1_sdai, 163 | I2C2SCLI => scuba_vlo, 164 | I2C2SDAI => scuba_vlo, 165 | SPISCKI => scuba_vlo, 166 | SPIMISOI => scuba_vlo, 167 | SPIMOSII => scuba_vlo, 168 | SPISCSN => scuba_vlo, 169 | 170 | TCCLKI => wb_clk_i, 171 | TCRSTN => "not"(wb_rst_i), -- resets internal 16-bit clock 172 | TCIC => '0', -- input capture trigger event 173 | 174 | UFMSN => scuba_vhi, 175 | WBDATO7 => wb_dat_o(7), 176 | WBDATO6 => wb_dat_o(6), 177 | WBDATO5 => wb_dat_o(5), 178 | WBDATO4 => wb_dat_o(4), 179 | WBDATO3 => wb_dat_o(3), 180 | WBDATO2 => wb_dat_o(2), 181 | WBDATO1 => wb_dat_o(1), 182 | WBDATO0 => wb_dat_o(0), 183 | WBACKO => wb_ack_o, 184 | PLLCLKO => open, 185 | PLLRSTO => open, 186 | PLL0STBO => open, 187 | PLL1STBO => open, 188 | PLLWEO => open, 189 | PLLADRO4 => open, 190 | PLLADRO3 => open, 191 | PLLADRO2 => open, 192 | PLLADRO1 => open, 193 | PLLADRO0 => open, 194 | PLLDATO7 => open, 195 | PLLDATO6 => open, 196 | PLLDATO5 => open, 197 | PLLDATO4 => open, 198 | PLLDATO3 => open, 199 | PLLDATO2 => open, 200 | PLLDATO1 => open, 201 | PLLDATO0 => open, 202 | I2C1SCLO => i2c1_sclo, 203 | I2C1SCLOEN => i2c1_scloen, 204 | I2C1SDAO => i2c1_sdao, 205 | I2C1SDAOEN => i2c1_sdaoen, 206 | I2C2SCLO => open, 207 | I2C2SCLOEN => open, 208 | I2C2SDAO => open, 209 | I2C2SDAOEN => open, 210 | I2C1IRQO => i2c1_irqo, 211 | I2C2IRQO => open, 212 | SPISCKO => open, 213 | SPISCKEN => open, 214 | SPIMISOO => open, 215 | SPIMISOEN => open, 216 | SPIMOSIO => open, 217 | SPIMOSIEN => open, 218 | SPIMCSN7 => open, 219 | SPIMCSN6 => open, 220 | SPIMCSN5 => open, 221 | SPIMCSN4 => open, 222 | SPIMCSN3 => open, 223 | SPIMCSN2 => open, 224 | SPIMCSN1 => open, 225 | SPIMCSN0 => open, 226 | SPICSNEN => open, 227 | SPIIRQO => open, 228 | 229 | TCINT => open, 230 | TCOC => open, 231 | 232 | WBCUFMIRQ => open, 233 | CFGWAKE => open, 234 | CFGSTDBY => open ); 235 | 236 | end struct; 237 | -------------------------------------------------------------------------------- /firmware/common/pifwb.vhd: -------------------------------------------------------------------------------- 1 | ----------------------------------------------------------------------- 2 | -- pifwb.vhd Bugblat pif central Wishbone/control logic 3 | -- 4 | -- Initial entry: 05-Jan-12 te 5 | -- Copyright (c) 2001 to 2013 te 6 | -- 7 | ----------------------------------------------------------------------- 8 | -- read sequence via i2c 9 | -- i2c transaction : addr, rd_data, rd_data, rd_data, ... 10 | -- 11 | ----------------------------------------------------------------------- 12 | -- write sequence via i2c 13 | -- i2c transaction is : addr, wr_data, wr_data, wr_data, ... 14 | -- 15 | -- wr_data is 16 | -- bits 7..6 : 00 - load address register - 64 registers, 16 used 17 | -- 01 - load data register 18 | -- 10 - reserved (was tx count) 19 | -- 11 - reserved 20 | -- bits 5..0 : data value 21 | -- 22 | ----------------------------------------------------------------------- 23 | library ieee; use ieee.std_logic_1164.all; 24 | use ieee.numeric_std.all; 25 | library work; use work.defs.all; 26 | library machxo2; use machxo2.components.all; 27 | 28 | entity pifwb is 29 | port ( 30 | i2c_SCL : inout std_logic; 31 | i2c_SDA : inout std_logic; 32 | xclk : in std_logic; 33 | XI : out XIrec; 34 | XO : in slv8 ); 35 | end pifwb; 36 | 37 | architecture rtl of pifwb is 38 | 39 | --------------------------------------------------------------------- 40 | component efbx is port ( 41 | wb_clk_i : in std_logic; 42 | wb_rst_i : in std_logic; 43 | wb_cyc_i : in std_logic; 44 | wb_stb_i : in std_logic; 45 | wb_we_i : in std_logic; 46 | wb_adr_i : in std_logic_vector(7 downto 0); 47 | wb_dat_i : in std_logic_vector(7 downto 0); 48 | wb_dat_o : out std_logic_vector(7 downto 0); 49 | wb_ack_o : out std_logic; 50 | i2c1_scl : inout std_logic; 51 | i2c1_sda : inout std_logic; 52 | i2c1_irqo : out std_logic ); 53 | end component efbx; 54 | --------------------------------------------------------------------- 55 | signal wbCyc 56 | , wbStb 57 | , wbWe 58 | , wbAck_o : std_logic; 59 | signal wbDat_o 60 | , wbDat_i 61 | , wbAddr 62 | , wbOutBuff : slv8 := (others=>'0'); 63 | 64 | -- quasi-static data out from the USB 65 | signal Xiloc : XIrec; -- local copy of XI 66 | signal rst : boolean := true; -- assume initialiser is honoured 67 | 68 | begin 69 | --------------------------------------------------------------------- 70 | -- Power-Up Reset for 16 clocks 71 | -- assumes initialisers are honoured by the synthesiser 72 | RST_BLK: block 73 | signal nrst : boolean := false; 74 | signal rst_count : integer range 0 to 15 := 0; 75 | begin 76 | process (xclk) begin 77 | if rising_edge(xclk) then 78 | if rst_count /= 15 then 79 | rst_count <= rst_count +1; 80 | end if; 81 | nrst <= rst_count=15; 82 | rst <= not nrst; 83 | end if; 84 | end process; 85 | end block RST_BLK; 86 | 87 | ------------------------------------------------ 88 | -- wishbone state machine 89 | WBSM_B: block 90 | 91 | type TWBstate is ( WBstart, 92 | WBinit1, WBinit2, WBinit3, WBinit4, 93 | WBidle, 94 | WBwaitTR, 95 | WBin0, WBout0, WBout1, 96 | WBwr, WBrd ); 97 | 98 | signal WBstate, rwReturn : TWBstate; 99 | 100 | signal busy, txReady, rxReady, lastTxNak, wbAck, isAddr, isData : boolean; 101 | 102 | -- wishbone/EFB addresses 103 | constant I2C1_CR : slv8 := x"40"; 104 | constant I2C1_CMDR : slv8 := x"41"; 105 | constant I2C1_BR0 : slv8 := x"42"; 106 | constant I2C1_BR1 : slv8 := x"43"; 107 | constant I2C1_TXDR : slv8 := x"44"; 108 | constant I2C1_SR : slv8 := x"45"; 109 | constant I2C1_GCDR : slv8 := x"46"; 110 | constant I2C1_RXDR : slv8 := x"47"; 111 | constant I2C1_IRQ : slv8 := x"48"; 112 | constant I2C1_IRQEN : slv8 := x"49"; 113 | 114 | constant I2C2_CR : slv8 := x"4A"; 115 | constant I2C2_CMDR : slv8 := x"4B"; 116 | constant I2C2_BR0 : slv8 := x"4C"; 117 | constant I2C2_BR1 : slv8 := x"4D"; 118 | constant I2C2_TXDR : slv8 := x"4E"; 119 | constant I2C2_SR : slv8 := x"4F"; 120 | constant I2C2_GCDR : slv8 := x"50"; 121 | constant I2C2_RXDR : slv8 := x"51"; 122 | constant I2C2_IRQ : slv8 := x"52"; 123 | constant I2C2_IRQEN : slv8 := x"53"; 124 | 125 | constant CFG_CR : slv8 := x"70"; 126 | constant CFG_TXDR : slv8 := x"71"; 127 | constant CFG_SR : slv8 := x"72"; 128 | constant CFG_RXDR : slv8 := x"73"; 129 | constant CFG_IRQ : slv8 := x"74"; 130 | constant CFG_IRQEN : slv8 := x"75"; 131 | 132 | signal hitI2CSR 133 | , hitI2CRXDR 134 | , hitCFGRXDR 135 | , cfgBusy : boolean; 136 | signal RdSubAddr 137 | , WrSubAddr : TXSubA; -- sub-addresses 138 | signal rwAddr : TXA; 139 | signal inData : TwrData; 140 | signal wbRst : std_logic; 141 | 142 | begin 143 | -- used in debug mode to reset the internal 16-bit counters 144 | wbRst <= '0' 145 | -- synthesis translate_off 146 | or (to_sl(rst)) 147 | -- synthesis translate_on 148 | ; 149 | myEFB: efbx port map ( wb_clk_i => xclk, 150 | wb_rst_i => wbRst, 151 | wb_cyc_i => wbCyc, 152 | wb_stb_i => wbStb, 153 | wb_we_i => wbWe, 154 | wb_adr_i => wbAddr, 155 | wb_dat_i => wbDat_i, 156 | wb_dat_o => wbDat_o, 157 | wb_ack_o => wbAck_o, 158 | i2c1_scl => i2c_SCL, 159 | i2c1_sda => i2c_SDA, 160 | i2c1_irqo => open ); 161 | 162 | wbAck <= (wbAck_o = '1'); 163 | 164 | process (xclk) 165 | variable nextState : TWBstate; 166 | variable vSlaveTransmitting 167 | , vTxRxRdy 168 | , vBusy 169 | , vTIP 170 | , vRARC 171 | , vTROE : boolean; 172 | variable vInst : slv8; 173 | 174 | ----------------------------------------------------- 175 | procedure Wr(addr:slv8; din:slv8; retState:TWBstate) is 176 | begin 177 | wbAddr <= addr; 178 | wbDat_i <= din; 179 | rwReturn <= retState; 180 | nextState := WBwr; 181 | end procedure Wr; 182 | 183 | ----------------------------------------------------- 184 | procedure Rd(addr:slv8; retState:TWBstate) is 185 | begin 186 | wbAddr <= addr; 187 | wbDat_i <= (others=>'0'); 188 | rwReturn <= retState; 189 | nextState := WBrd; 190 | end procedure Rd; 191 | 192 | ----------------------------------------------------- 193 | procedure ReadRegAgain is 194 | begin 195 | nextState := WBrd; 196 | end procedure ReadRegAgain; 197 | 198 | ----------------------------------------------------- 199 | 200 | begin 201 | if rising_edge(xclk) then 202 | nextState := WBstate; 203 | hitI2CSR <= (wbAddr = I2C1_SR ); 204 | hitI2CRXDR <= (wbAddr = I2C1_RXDR); 205 | hitCFGRXDR <= (wbAddr = CFG_RXDR); 206 | 207 | if rst then 208 | nextState := WBstart; 209 | rwReturn <= WBstart; 210 | wbStb <= '0'; 211 | wbCyc <= '0'; 212 | wbWe <= '0'; 213 | busy <= false; 214 | txReady <= false; 215 | rxReady <= false; 216 | lastTxNak <= false; 217 | rwAddr <= 0; 218 | RdSubAddr <= 0; 219 | WrSubAddr <= 0; 220 | else 221 | case WBstate is 222 | ----------------------------------- 223 | -- initialise 224 | when WBstart => 225 | Wr(I2C1_CMDR, x"04", WBinit1); -- clock stretch disable 226 | 227 | when WBinit1 => 228 | Rd(I2C1_SR, WBinit2); -- wait for not busy 229 | 230 | when WBinit2 => 231 | if busy then 232 | ReadRegAgain; 233 | else 234 | Rd(I2C1_RXDR, WBinit3); -- read and discard RXDR, #1 235 | end if; 236 | 237 | when WBinit3 => 238 | Rd(I2C1_RXDR, WBinit4); -- read and discard RXDR, #2 239 | 240 | when WBinit4 => 241 | Wr(I2C1_CMDR, x"00", WBidle); -- clock stretch enable 242 | 243 | ----------------------------------- 244 | -- wait for I2C activity - "busy" is signalled 245 | when WBidle => 246 | if busy then -- I2C bus active? 247 | Rd(I2C1_SR, WBwaitTR); 248 | else 249 | Rd(I2C1_SR, WBidle); 250 | end if; 251 | 252 | ----------------------------------- 253 | -- wait for TRRDY 254 | when WBwaitTR => 255 | if lastTxNak then -- last read? 256 | nextState := WBstart; 257 | elsif txReady then 258 | Wr(I2C1_TXDR, XO, WBout0); 259 | elsif rxReady then 260 | Rd(I2C1_RXDR, WBin0); 261 | elsif not busy then 262 | nextState := WBstart; 263 | else 264 | ReadRegAgain; 265 | end if; 266 | 267 | ----------------------------------- 268 | -- incoming data 269 | when WBin0 => 270 | nextState := WBidle; 271 | 272 | ----------------------------------- 273 | -- outgoing data 274 | when WBout0 => 275 | nextState := WBout1; 276 | 277 | when WBout1 => 278 | nextState := WBidle; 279 | 280 | ----------------------------------- 281 | -- read cycle 282 | when WBrd => 283 | if wbAck then 284 | wbStb <= '0'; 285 | wbCyc <= '0'; 286 | if hitI2CSR then 287 | vTIP := (wbDat_o(7) = '1'); 288 | vBusy := (wbDat_o(6) = '1'); 289 | vRARC := (wbDat_o(5) = '1'); 290 | vSlaveTransmitting := (wbDat_o(4) = '1'); 291 | vTxRxRdy := (wbDat_o(2) = '1'); 292 | vTROE := (wbDat_o(1) = '1'); 293 | txReady <= vBusy and (vTxRxRdy and vSlaveTransmitting and not vTIP ); 294 | rxReady <= vBusy and (vTxRxRdy and not vSlaveTransmitting ); 295 | lastTxNak <= vBusy and (vRARC and vSlaveTransmitting and vTROE); 296 | busy <= vBusy; 297 | end if; 298 | if hitI2CRXDR then 299 | isAddr <= (wbDat_o(TincomingTypeRange) = A_ADDR); 300 | isData <= (wbDat_o(TincomingTypeRange) = D_ADDR); 301 | inData <= wbDat_o(TincomingDataRange); 302 | end if; 303 | if hitCFGRXDR then 304 | cfgBusy <= (wbDat_o(7) = '1'); 305 | end if; 306 | 307 | wbOutBuff <= wbDat_o; 308 | nextState := rwReturn; 309 | else 310 | wbStb <= '1'; 311 | wbCyc <= '1'; 312 | end if; 313 | 314 | ----------------------------------- 315 | -- write cycle 316 | when WBwr => 317 | if wbAck then 318 | wbStb <= '0'; 319 | wbCyc <= '0'; 320 | wbWe <= '0'; 321 | nextState := rwReturn; 322 | else 323 | wbStb <= '1'; 324 | wbCyc <= '1'; 325 | wbWe <= '1'; 326 | end if; 327 | 328 | ----------------------------------- 329 | -- when others => 330 | -- nextState := WBstart; 331 | 332 | end case; 333 | end if; 334 | 335 | XiLoc.PRdFinished <= (WBstate = WBout0); 336 | 337 | if (WBstate = WBin0) and isAddr then 338 | rwAddr <= ToInteger(inData(TXARange)); 339 | end if; 340 | 341 | if (WBstate = WBin0) and isAddr then 342 | RdSubAddr <= 0; 343 | elsif XiLoc.PRdFinished then 344 | RdSubAddr <= (RdSubAddr +1) mod (XSUBA_MAX+1); 345 | end if; 346 | 347 | if (WBstate = WBin0) and isAddr then 348 | WrSubAddr <= 0; 349 | elsif XiLoc.PWr then 350 | WrSubAddr <= (WrSubAddr +1) mod (XSUBA_MAX+1); 351 | end if; 352 | 353 | if (WBstate = WBin0) and isData then 354 | XiLoc.PD <= inData; 355 | XiLoc.PWr <= true; 356 | else 357 | XiLoc.PWr <= false; 358 | end if; 359 | 360 | WBstate <= nextState; 361 | end if; 362 | end process; 363 | 364 | XiLoc.PRWA <= rwAddr; 365 | XiLoc.PRdSubA <= RdSubAddr; 366 | 367 | end block WBSM_B; 368 | 369 | XI <= XIloc; 370 | 371 | end rtl; 372 | 373 | ----------------------------------------------------------------------- 374 | -- EOF pifwb.vhd 375 | -------------------------------------------------------------------------------- /firmware/common/flashctl_tb.vhd: -------------------------------------------------------------------------------- 1 | -- testbench for flasher xo2 design 2 | -- ============================================================ 3 | library ieee; use ieee.std_logic_1164.all; 4 | use ieee.NUMERIC_STD.all; 5 | use ieee.std_logic_textio.all; 6 | use std.textio.all; 7 | 8 | library work; use work.defs.all; 9 | 10 | entity test is 11 | end test; 12 | 13 | --------------------------------------------------------------- 14 | architecture test_arch of test is 15 | 16 | constant MAX_BUF : integer := 250; 17 | type Tdata is array (0 to MAX_BUF) of integer; 18 | 19 | type Tbuf is record 20 | count : integer; 21 | data : Tdata; 22 | end record Tbuf; 23 | 24 | constant MAX_KEYLEN : integer := 8; -- keyword length 25 | constant MAX_LINE : integer := 132; -- input or output 26 | 27 | function ToUpper( x : string ) return string is 28 | variable s : string(1 to x'length); 29 | variable c: character; 30 | variable p: integer; 31 | begin 32 | for i in 1 to x'length loop 33 | c := x(i); 34 | p := character'pos(c); 35 | if p >= character'pos('a') and p <= character'pos('z') then 36 | p := p + character'pos('A') - character'pos('a'); 37 | end if; 38 | s(i) := character'val(p); 39 | end loop; 40 | return s; 41 | end ToUpper; 42 | 43 | function str( x : std_logic_vector ) return string is 44 | variable r : line; 45 | variable s : string(1 to x'length) := (others => ' '); 46 | begin 47 | write( r, x ); 48 | s(r.all'range) := r.all; 49 | deallocate(r); 50 | return s; 51 | end str; 52 | 53 | function str( x : integer ) return string is 54 | variable u : unsigned(31 downto 0); 55 | begin 56 | u := to_unsigned(x,32); 57 | return str(std_logic_vector(u)); 58 | end str; 59 | 60 | function hstr( x : std_logic_vector ) return string is 61 | variable r : line; 62 | variable s : string(1 to (x'length)/4) := (others => ' '); 63 | begin 64 | hwrite( r, x ); 65 | s(r.all'range) := r.all; 66 | deallocate(r); 67 | return "0x" & s; 68 | end hstr; 69 | 70 | function hstr( x : unsigned ) return string is 71 | begin 72 | return hstr(std_logic_vector(x)); 73 | end hstr; 74 | 75 | function hstr( x : integer ) return string is 76 | variable u : unsigned(31 downto 0); 77 | begin 78 | u := to_unsigned(x,32); 79 | return hstr(std_logic_vector(u)); 80 | end hstr; 81 | 82 | function hstr8( x : integer ) return string is 83 | variable u : unsigned(7 downto 0); 84 | begin 85 | u := to_unsigned(x,8); 86 | return hstr(std_logic_vector(u)); 87 | end hstr8; 88 | 89 | function nstr( n : integer; len: integer ) return string is 90 | variable r : line; 91 | variable s : string(1 to len); 92 | begin 93 | write( r, n ); 94 | s(r.all'range) := r.all; 95 | deallocate(r); 96 | return s; 97 | end nstr; 98 | 99 | signal TestFinished : boolean := false; -- set 'true' at end of sim 100 | 101 | component flasher is port ( 102 | SCL, 103 | SDA : inout std_logic; 104 | GSRn : in std_logic; 105 | LEDR, 106 | LEDG : out std_logic 107 | ); 108 | end component flasher; 109 | 110 | ----------------------------------------------------------------------- 111 | signal ExtClock, 112 | RSTn : std_logic := '0'; 113 | 114 | signal RedLedn, GreenLedn : std_logic; 115 | signal TrigInPad, ClkInPad : std_logic := '0'; 116 | 117 | signal outBuf, inBuf : Tbuf; 118 | 119 | --------------------------------------------- 120 | -- I2C 121 | signal i2cSCL, i2cSDA : std_logic := 'H'; 122 | signal i2c_sclIn, i2c_sdaIn, 123 | i2c_din : std_logic := '0'; 124 | signal i2c_sclOut, i2c_sdaOut : std_logic := '1'; 125 | signal i2c_addr : slv8 := x"82"; 126 | signal i2cToggle : boolean := true; 127 | signal i2cAckn : std_logic; 128 | 129 | signal obSig : Tbuf := (count=>0, data=>(others=>0)); 130 | --------------------------------------------- 131 | begin 132 | -- instantiate the design 133 | UUT : flasher port map ( SCL => i2cSCL 134 | , SDA => i2cSDA 135 | , GSRn => RSTn 136 | , LEDR => RedLedn 137 | , LEDG => GreenLedn 138 | ); 139 | 140 | i2cSCL <= 'H'; 141 | i2cSDA <= 'H'; 142 | 143 | EXT_CLK: process 144 | constant E_PERIOD: time := 50 ns; 145 | begin 146 | ExtClock <= '0'; wait for E_PERIOD/2; 147 | ExtClock <= '1'; wait for E_PERIOD/2; 148 | if TestFinished then wait; end if; 149 | end process EXT_CLK; 150 | 151 | i2cSCL <= '0' when i2c_sclOut='0' else 'Z'; 152 | i2cSDA <= '0' when i2c_sdaOut='0' else 'Z'; 153 | 154 | i2c_sdaIn <= to_x01(i2cSDA); 155 | i2c_sclIn <= to_x01(i2cSCL); 156 | 157 | process (i2c_sclIn) begin 158 | if rising_edge(i2c_sclIn) then 159 | i2c_din <= i2c_sdaIn; 160 | end if; 161 | end process; 162 | 163 | -- ============================================================ 164 | -- main testbench 'stimulus' process 165 | -- ============================================================ 166 | STIMULUS: process 167 | 168 | variable Lin,Lout : line; 169 | variable LineNum : natural := 0; 170 | variable keyword : string(1 to MAX_KEYLEN); 171 | variable Reg,Val,x : integer := 0; 172 | variable v0,v1,v2,v3,v4,v5,v6 : integer := 0; 173 | variable len : integer; 174 | 175 | variable Ibuff : string(1 to MAX_LINE); 176 | variable Ibuffstrt : integer; 177 | variable Ibuffend : integer; 178 | 179 | constant x1 : time := 2500 ns; -- i2c clock 180 | constant x2 : time := x1 / 2; 181 | 182 | variable outBuf : Tbuf := (count=>0, data=>(others=>0)); 183 | 184 | function ToUpper(ch: character) return character is 185 | variable c: character; 186 | begin 187 | c := ch; 188 | if c>='a' and c<='z' then 189 | c :=character'val( character'pos(c) 190 | + character'pos('A') 191 | - character'pos('a') ); 192 | end if; 193 | return c; 194 | end function ToUpper; 195 | 196 | procedure GetCh(ch: out character; good: out boolean) is 197 | begin 198 | if Ibuffstrt <= Ibuffend then 199 | ch := Ibuff(Ibuffstrt); 200 | Ibuffstrt := Ibuffstrt+1; 201 | good := true; 202 | else 203 | ch := ';'; 204 | good := false; 205 | end if; 206 | end procedure GetCh; 207 | 208 | function IsWS(c: character) return boolean is 209 | begin 210 | return (c=' ' or c=HT); 211 | end function IsWS; 212 | 213 | procedure PutBack(c : character) is 214 | begin 215 | Ibuffstrt := Ibuffstrt-1; 216 | Ibuff(Ibuffstrt) := c; 217 | end procedure PutBack; 218 | 219 | procedure SkipSpaces is 220 | variable c: character; 221 | variable good: boolean; 222 | begin 223 | -- eat the leading spaces 224 | L: loop 225 | GetCh(c, good); 226 | exit L when not good; 227 | if not IsWS(c) then 228 | PutBack(c); 229 | exit L; 230 | end if; 231 | end loop L; 232 | end; 233 | 234 | impure function InputStr return string is 235 | variable n : integer := 0; 236 | variable c: character; 237 | variable good: boolean; 238 | variable s: string(1 to MAX_LINE); -- := (others=>' '); 239 | begin 240 | SkipSpaces; 241 | L: loop 242 | GetCh(c, good); 243 | exit L when not good; 244 | exit L when IsWS(c); 245 | n := n+1; 246 | s(n) := c; 247 | end loop L; 248 | return s(1 to n); 249 | end function InputStr; 250 | 251 | procedure ReadKeyword(str: out string) is 252 | variable s : string(1 to str'length); 253 | variable n : integer; 254 | begin 255 | for i in 1 to s'length loop 256 | s(i) := '_'; 257 | end loop; 258 | SkipSpaces; 259 | -- read the keyword 260 | n := 0; 261 | while (Ibuff(Ibuffstrt) /= ' ') 262 | and (Ibuff(Ibuffstrt) /= HT) 263 | and (Ibuffstrt <= Ibuffend) loop 264 | n := n+1; 265 | if n <= str'length then 266 | s(n) := Ibuff(Ibuffstrt); -- don't want to overflow 267 | end if; 268 | Ibuffstrt := Ibuffstrt+1; 269 | end loop; 270 | str := s; 271 | end ReadKeyword; 272 | 273 | procedure InputDecAsInt( x: out integer) is 274 | variable c : character; 275 | variable n : integer := 0; 276 | begin 277 | SkipSpaces; 278 | while (Ibuff(Ibuffstrt) >= '0') 279 | and (Ibuff(Ibuffstrt) <= '9') 280 | and (Ibuffstrt <= Ibuffend) loop 281 | c := Ibuff(Ibuffstrt); 282 | n := n*10 + character'pos(c) - character'pos('0'); 283 | Ibuffstrt := Ibuffstrt+1; 284 | end loop; 285 | x := n; 286 | end InputDecAsInt; 287 | 288 | procedure InputHexAsInt( x: out integer) is 289 | variable n : integer := 0; 290 | variable c : character; 291 | begin 292 | SkipSpaces; 293 | while Ibuffstrt <= Ibuffend loop 294 | c := Ibuff(Ibuffstrt); 295 | if '0' <= c and c <= '9' then 296 | n := n*16 + character'pos(c) - character'pos('0'); 297 | elsif 'A' <= c and c <= 'F' then 298 | n := n*16 + character'pos(c) - character'pos('A') + 10; 299 | elsif 'a' <= c and c <= 'f' then 300 | n := n*16 + character'pos(c) - character'pos('a') + 10; 301 | else exit; 302 | end if; 303 | Ibuffstrt := Ibuffstrt+1; 304 | end loop; 305 | x := n; 306 | end InputHexAsInt; 307 | 308 | procedure InputHexAsSLV32( x: out slv32) is 309 | variable n : integer; 310 | variable sn: slv4; 311 | variable r : slv32 := (others=>'0'); 312 | variable c : character; 313 | variable i : integer := 0; 314 | begin 315 | SkipSpaces; 316 | while Ibuffstrt <= Ibuffend and i<8 loop 317 | c := Ibuff(Ibuffstrt); 318 | if '0' <= c and c <= '9' then 319 | n := character'pos(c) - character'pos('0'); 320 | elsif 'A' <= c and c <= 'F' then 321 | n := character'pos(c) - character'pos('A') + 10; 322 | elsif 'a' <= c and c <= 'f' then 323 | n := character'pos(c) - character'pos('a') + 10; 324 | else exit; 325 | end if; 326 | sn := n2slv(n, 4); 327 | r := r(27 downto 0) & sn; 328 | Ibuffstrt := Ibuffstrt+1; 329 | i := i+1; 330 | end loop; 331 | x := r; 332 | end InputHexAsSLV32; 333 | 334 | procedure Inputline( Lin : inout line; 335 | str: out string; len: out integer) is 336 | variable s : string(1 to MAX_LINE); 337 | variable c : character; 338 | variable n : integer; 339 | begin 340 | n := Lin'length; 341 | L: for i in 1 to n loop 342 | read(Lin,c); 343 | s(i) := ToUpper(c); 344 | end loop L; 345 | str := s; 346 | len := n; 347 | end Inputline; 348 | 349 | procedure WaitFor ( n : natural ) is 350 | begin 351 | for i in 1 to n loop 352 | wait until rising_edge(ExtClock); -- wait for n clocks 353 | end loop; 354 | end; 355 | 356 | procedure write_string(L: inout line; v: in string) is 357 | begin 358 | write(L, v); 359 | end write_string; 360 | 361 | --------------------------------------------- 362 | -- <--- i2cStart ----> or <-- Rep i2cStart -> 363 | -- time | | | | | | | | 364 | -- sda ~~~~~~~~~~\_____ __/~~~~~~~\_____ 365 | -- scl __/~~~~~~~~~~~\__ ______/~~~~~~~\__ 366 | procedure i2cStart is 367 | begin 368 | i2c_sdaOut <= '1'; wait for x2; 369 | i2c_sclOut <= '1'; wait for x2; 370 | i2c_sdaOut <= '0'; wait for x2; 371 | i2c_sclOut <= '0'; wait for x2; 372 | end procedure i2cStart; 373 | 374 | --------------------------------------------- 375 | -- time | | | | or | | | | 376 | -- sda __________/~~~ ~~~~\______/~~~ 377 | -- scl ______/~~~~~~~ ______/~~~~~~~ 378 | procedure i2cStop is 379 | begin 380 | i2c_sdaOut <= '0'; wait for x2; 381 | i2c_sclOut <= '1'; wait for x2; 382 | i2c_sdaOut <= '1'; wait for x2; 383 | end procedure i2cStop; 384 | 385 | --------------------------------------------- 386 | -- time | | | | 387 | -- sda a bbbbbbbbbbb 388 | -- scl _____/~~~\___ 389 | procedure i2cSendBit(b:std_logic) is 390 | begin 391 | i2c_sdaOut <= b ; wait for x2; 392 | i2c_sclOut <= '1'; wait for x2; 393 | i2c_sclOut <= '0'; wait for x2; 394 | end procedure i2cSendBit; 395 | 396 | --------------------------------------------- 397 | procedure i2cDoClock is 398 | begin 399 | i2c_sclOut <= '0'; wait for x2; 400 | i2c_sclOut <= '1'; wait for x2; 401 | i2c_sclOut <= '0'; wait for x2; 402 | end procedure i2cDoClock; 403 | 404 | --------------------------------------------- 405 | procedure i2cSendByte(v:slv8) is 406 | begin 407 | for i in 7 downto 0 loop 408 | i2cSendBit(v(i)); 409 | end loop; 410 | 411 | i2cDoClock; -- after this, ack=0/nak=1 in i2c_din 412 | --wait for x2 * 4; 413 | i2cAckn <= i2c_din; 414 | i2cToggle <= not i2cToggle; 415 | end procedure i2cSendByte; 416 | 417 | --------------------------------------------- 418 | procedure i2cRecvBit(v: out slv8; i2cAckn:std_logic) is 419 | variable bi : slv8; 420 | begin 421 | bi := (others=>'0'); 422 | for i in 7 downto 0 loop 423 | i2cSendBit('1'); 424 | bi := bi(6 downto 0) & i2c_din; 425 | end loop; 426 | 427 | i2cSendBit(i2cAckn); -- send ack=0/nak=1 428 | 429 | --wait for x2 * 4; 430 | v := bi; 431 | i2cToggle <= not i2cToggle; 432 | end procedure i2cRecvBit; 433 | 434 | --------------------------------------------- 435 | procedure i2cWrStart is begin 436 | i2cStart; 437 | i2cSendByte(i2c_addr(7 downto 1) & '0'); 438 | end i2cWrStart; 439 | 440 | --------------------------------------------- 441 | procedure i2cRdStart is begin 442 | i2cStart; 443 | i2cSendByte(i2c_addr(7 downto 1) & '1'); 444 | end i2cRdStart; 445 | 446 | --------------------------------------------- 447 | procedure writeBus(x : in slv8) is 448 | variable n: integer; 449 | begin 450 | n := outBuf.count; 451 | outBuf.data(n) := ToInteger(x); 452 | outBuf.count := n + 1; 453 | obSig <= outBuf; 454 | WaitFor(1); 455 | end writeBus; 456 | 457 | procedure writeD(V : in TwrData) is 458 | begin 459 | writeBus(D_ADDR & V); 460 | end writeD; 461 | 462 | procedure writeD(V : in integer) is 463 | variable x: TwrData; 464 | begin 465 | x := n2slv(V,I2C_DATA_BITS); 466 | writeD(x); 467 | end writeD; 468 | 469 | procedure writexD(x : in slv8) is 470 | begin 471 | writeD(ToInteger(x)); 472 | end writexD; 473 | 474 | procedure writeA(Addr: in integer) is 475 | begin 476 | writeBus(A_ADDR & n2slv(Addr,I2C_DATA_BITS)); 477 | end writeA; 478 | 479 | --------------------------------------------- 480 | procedure flush is 481 | variable n : integer; 482 | begin 483 | n := outBuf.count; 484 | if n>0 then 485 | WaitFor(1); 486 | wait for 5 ns; 487 | i2cWrStart; 488 | for i in 0 to (n-1) loop 489 | i2cSendByte(n2slv(outBuf.data(i), 8)); 490 | outBuf.count := outBuf.count -1; 491 | obSig <= outBuf; 492 | end loop; 493 | i2cStop; 494 | end if; 495 | end flush; 496 | 497 | --------------------------------------------- 498 | procedure readReg(rdCount:integer) is 499 | variable i2cAckn : std_logic; 500 | variable v : slv8; 501 | begin 502 | i2cRdStart; 503 | for i in 0 to (rdCount-1) loop 504 | if i < (rdCount-1) then 505 | i2cAckn := '0'; 506 | else 507 | i2cAckn := '1'; 508 | end if; 509 | i2cRecvBit(v, i2cAckn); 510 | write_string(Lout, ". Value: " & hstr8(ToInteger(v))); 511 | end loop; 512 | i2cStop; 513 | end readReg; 514 | 515 | ------------------------------------------------------------------ 516 | variable dummy : integer; 517 | variable trace : boolean := true; 518 | variable Count : integer; 519 | 520 | file CommandFile : text; 521 | 522 | ----------------------------- 523 | -- body of process 'STIMULUS' 524 | ----------------------------- 525 | -- read: 526 | -- read hex_addr decimal_num 527 | -- results in the rdData array 528 | -- data to wrData array 529 | -- data hex_data 530 | -- address to wrData array 531 | -- addr hex_addr 532 | -- write: 533 | -- write 534 | -- takes data from the wrData array 535 | begin 536 | TestFinished <= false; 537 | 538 | write_string(Lout,"Resetting..."); 539 | writeline(OUTPUT, Lout); 540 | RSTn <= '0'; 541 | wait for 100 ns; 542 | RSTn <= '1'; 543 | 544 | write_string(Lout,"Running..."); 545 | writeline(OUTPUT, Lout); 546 | wait for 50 ns; 547 | 548 | file_open(CommandFile, "..\..\test.txt", read_mode); 549 | MainLoop: loop 550 | exit MainLoop when endfile(CommandFile); 551 | readline(CommandFile, Lin); 552 | LineNum := LineNum + 1; 553 | 554 | next MainLoop when Lin'length=0; -- skip empty lines 555 | InputLine(Lin, Ibuff, Ibuffend); 556 | Ibuffstrt := 1; 557 | 558 | ReadKeyword(keyword); 559 | if trace then 560 | write_string(Lout, "Tr: " & keyword & " Ln "); 561 | write(Lout, LineNum); 562 | write_string(Lout, ". " & Ibuff ); 563 | writeline(OUTPUT, Lout); 564 | end if; 565 | next MainLoop when keyword(2)='_'; -- skip junk line at some file ends 566 | 567 | case keyword is 568 | when "REM_____" => 569 | dummy := 0; -- for debugging 570 | when "WRITE_A_" => 571 | InputDecAsInt(Val); 572 | writeA(Val); 573 | when "WRITE_D_" => 574 | InputHexAsInt(Val); 575 | writeD(Val); 576 | when "FLUSH___" => 577 | flush; 578 | when "READ____" => 579 | InputDecAsInt(Reg); 580 | writeA(Reg); 581 | flush; 582 | write_string(Lout, " Read of register "); 583 | write(Lout, Reg ); 584 | ReadReg(1); 585 | writeline(OUTPUT, Lout); 586 | when "READMULT" => 587 | InputDecAsInt(Reg); 588 | InputDecAsInt(Count); 589 | writeA(Reg); 590 | flush; 591 | write_string(Lout, " Read multiple ("); 592 | write(Lout, Count ); 593 | write_string(Lout, ") of register "); 594 | write(Lout, Reg ); 595 | ReadReg(Count); 596 | writeline(OUTPUT, Lout); 597 | when "ECHO____" => 598 | SkipSpaces; 599 | write_string(Lout, Ibuff(Ibuffstrt to Ibuffend)); 600 | writeline(OUTPUT, Lout); 601 | when "TRACE___" => 602 | InputDecAsInt(Val); 603 | trace := Val/=0; 604 | when "QUIT____" => 605 | write_string(Lout," QUIT command seen. Exiting."); 606 | writeline(OUTPUT, Lout); 607 | exit MainLoop; 608 | when others => 609 | assert false 610 | report "Unexpected command: " & keyword 611 | severity ERROR; 612 | end case; 613 | 614 | end loop MainLoop; 615 | file_close(CommandFile); 616 | 617 | WaitFor(10); 618 | TestFinished <= true; 619 | wait; -- Suspend simulation 620 | 621 | end process STIMULUS; 622 | end test_arch; 623 | -- EOF -------------------------------------------------------- 624 | -------------------------------------------------------------------------------- /software/src/bcm2835.c: -------------------------------------------------------------------------------- 1 | /* bcm2835.c 2 | // C and C++ support for Broadcom BCM 2835 as used in Raspberry Pi 3 | // http://elinux.org/RPi_Low-level_peripherals 4 | // http://www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-Peripherals.pdf 5 | // 6 | // Author: Mike McCauley 7 | // Copyright (C) 2011-2013 Mike McCauley 8 | // $Id: bcm2835.c,v 1.23 2015/03/31 04:55:41 mikem Exp mikem $ 9 | */ 10 | 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #define BCK2835_LIBRARY_BUILD 23 | #include "bcm2835.h" 24 | 25 | /* This define enables a little test program (by default a blinking output on pin RPI_GPIO_PIN_11) 26 | // You can do some safe, non-destructive testing on any platform with: 27 | // gcc bcm2835.c -D BCM2835_TEST 28 | // ./a.out 29 | */ 30 | /*#define BCM2835_TEST*/ 31 | 32 | /* Uncommenting this define compiles alternative I2C code for the version 1 RPi 33 | // The P1 header I2C pins are connected to SDA0 and SCL0 on V1. 34 | // By default I2C code is generated for the V2 RPi which has SDA1 and SCL1 connected. 35 | */ 36 | /* #define I2C_V1*/ 37 | 38 | /* Physical address and size of the peripherals block 39 | // May be overridden on RPi2 40 | */ 41 | uint32_t *bcm2835_peripherals_base = (uint32_t *)BCM2835_PERI_BASE; 42 | uint32_t bcm2835_peripherals_size = BCM2835_PERI_SIZE; 43 | 44 | /* Virtual memory address of the mapped peripherals block 45 | */ 46 | uint32_t *bcm2835_peripherals = (uint32_t *)MAP_FAILED; 47 | 48 | /* And the register bases within the peripherals block 49 | */ 50 | volatile uint32_t *bcm2835_gpio = (uint32_t *)MAP_FAILED; 51 | volatile uint32_t *bcm2835_pwm = (uint32_t *)MAP_FAILED; 52 | volatile uint32_t *bcm2835_clk = (uint32_t *)MAP_FAILED; 53 | volatile uint32_t *bcm2835_pads = (uint32_t *)MAP_FAILED; 54 | volatile uint32_t *bcm2835_spi0 = (uint32_t *)MAP_FAILED; 55 | volatile uint32_t *bcm2835_bsc0 = (uint32_t *)MAP_FAILED; 56 | volatile uint32_t *bcm2835_bsc1 = (uint32_t *)MAP_FAILED; 57 | volatile uint32_t *bcm2835_st = (uint32_t *)MAP_FAILED; 58 | 59 | 60 | /* This variable allows us to test on hardware other than RPi. 61 | // It prevents access to the kernel memory, and does not do any peripheral access 62 | // Instead it prints out what it _would_ do if debug were 0 63 | */ 64 | static uint8_t debug = 0; 65 | 66 | /* I2C The time needed to transmit one byte. In microseconds. 67 | */ 68 | static int i2c_byte_wait_us = 0; 69 | 70 | /* 71 | // Low level register access functions 72 | */ 73 | 74 | /* Function to return the pointers to the hardware register bases */ 75 | uint32_t* bcm2835_regbase(uint8_t regbase) 76 | { 77 | switch (regbase) 78 | { 79 | case BCM2835_REGBASE_ST: 80 | return (uint32_t *)bcm2835_st; 81 | case BCM2835_REGBASE_GPIO: 82 | return (uint32_t *)bcm2835_gpio; 83 | case BCM2835_REGBASE_PWM: 84 | return (uint32_t *)bcm2835_pwm; 85 | case BCM2835_REGBASE_CLK: 86 | return (uint32_t *)bcm2835_clk; 87 | case BCM2835_REGBASE_PADS: 88 | return (uint32_t *)bcm2835_pads; 89 | case BCM2835_REGBASE_SPI0: 90 | return (uint32_t *)bcm2835_spi0; 91 | case BCM2835_REGBASE_BSC0: 92 | return (uint32_t *)bcm2835_bsc0; 93 | case BCM2835_REGBASE_BSC1: 94 | return (uint32_t *)bcm2835_st; 95 | } 96 | return (uint32_t *)MAP_FAILED; 97 | } 98 | 99 | void bcm2835_set_debug(uint8_t d) 100 | { 101 | debug = d; 102 | } 103 | 104 | unsigned int bcm2835_version(void) 105 | { 106 | return BCM2835_VERSION; 107 | } 108 | 109 | /* Read with memory barriers from peripheral 110 | * 111 | */ 112 | uint32_t bcm2835_peri_read(volatile uint32_t* paddr) 113 | { 114 | uint32_t ret; 115 | if (debug) 116 | { 117 | printf("bcm2835_peri_read paddr %08X\n", (unsigned) paddr); 118 | return 0; 119 | } 120 | else 121 | { 122 | __sync_synchronize(); 123 | ret = *paddr; 124 | __sync_synchronize(); 125 | return ret; 126 | } 127 | } 128 | 129 | /* read from peripheral without the read barrier 130 | * This can only be used if more reads to THE SAME peripheral 131 | * will follow. The sequence must terminate with memory barrier 132 | * before any read or write to another peripheral can occur. 133 | * The MB can be explicit, or one of the barrier read/write calls. 134 | */ 135 | uint32_t bcm2835_peri_read_nb(volatile uint32_t* paddr) 136 | { 137 | if (debug) 138 | { 139 | printf("bcm2835_peri_read_nb paddr %08X\n", (unsigned) paddr); 140 | return 0; 141 | } 142 | else 143 | { 144 | return *paddr; 145 | } 146 | } 147 | 148 | /* Write with memory barriers to peripheral 149 | */ 150 | 151 | void bcm2835_peri_write(volatile uint32_t* paddr, uint32_t value) 152 | { 153 | if (debug) 154 | { 155 | printf("bcm2835_peri_write paddr %08X, value %08X\n", (unsigned) paddr, value); 156 | } 157 | else 158 | { 159 | __sync_synchronize(); 160 | *paddr = value; 161 | __sync_synchronize(); 162 | } 163 | } 164 | 165 | /* write to peripheral without the write barrier */ 166 | void bcm2835_peri_write_nb(volatile uint32_t* paddr, uint32_t value) 167 | { 168 | if (debug) 169 | { 170 | printf("bcm2835_peri_write_nb paddr %08X, value %08X\n", 171 | (unsigned) paddr, value); 172 | } 173 | else 174 | { 175 | *paddr = value; 176 | } 177 | } 178 | 179 | /* Set/clear only the bits in value covered by the mask 180 | * This is not atomic - can be interrupted. 181 | */ 182 | void bcm2835_peri_set_bits(volatile uint32_t* paddr, uint32_t value, uint32_t mask) 183 | { 184 | uint32_t v = bcm2835_peri_read(paddr); 185 | v = (v & ~mask) | (value & mask); 186 | bcm2835_peri_write(paddr, v); 187 | } 188 | 189 | /* 190 | // Low level convenience functions 191 | */ 192 | 193 | /* Function select 194 | // pin is a BCM2835 GPIO pin number NOT RPi pin number 195 | // There are 6 control registers, each control the functions of a block 196 | // of 10 pins. 197 | // Each control register has 10 sets of 3 bits per GPIO pin: 198 | // 199 | // 000 = GPIO Pin X is an input 200 | // 001 = GPIO Pin X is an output 201 | // 100 = GPIO Pin X takes alternate function 0 202 | // 101 = GPIO Pin X takes alternate function 1 203 | // 110 = GPIO Pin X takes alternate function 2 204 | // 111 = GPIO Pin X takes alternate function 3 205 | // 011 = GPIO Pin X takes alternate function 4 206 | // 010 = GPIO Pin X takes alternate function 5 207 | // 208 | // So the 3 bits for port X are: 209 | // X / 10 + ((X % 10) * 3) 210 | */ 211 | void bcm2835_gpio_fsel(uint8_t pin, uint8_t mode) 212 | { 213 | /* Function selects are 10 pins per 32 bit word, 3 bits per pin */ 214 | volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPFSEL0/4 + (pin/10); 215 | uint8_t shift = (pin % 10) * 3; 216 | uint32_t mask = BCM2835_GPIO_FSEL_MASK << shift; 217 | uint32_t value = mode << shift; 218 | bcm2835_peri_set_bits(paddr, value, mask); 219 | } 220 | 221 | /* Set output pin */ 222 | void bcm2835_gpio_set(uint8_t pin) 223 | { 224 | volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPSET0/4 + pin/32; 225 | uint8_t shift = pin % 32; 226 | bcm2835_peri_write(paddr, 1 << shift); 227 | } 228 | 229 | /* Clear output pin */ 230 | void bcm2835_gpio_clr(uint8_t pin) 231 | { 232 | volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPCLR0/4 + pin/32; 233 | uint8_t shift = pin % 32; 234 | bcm2835_peri_write(paddr, 1 << shift); 235 | } 236 | 237 | /* Set all output pins in the mask */ 238 | void bcm2835_gpio_set_multi(uint32_t mask) 239 | { 240 | volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPSET0/4; 241 | bcm2835_peri_write(paddr, mask); 242 | } 243 | 244 | /* Clear all output pins in the mask */ 245 | void bcm2835_gpio_clr_multi(uint32_t mask) 246 | { 247 | volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPCLR0/4; 248 | bcm2835_peri_write(paddr, mask); 249 | } 250 | 251 | /* Read input pin */ 252 | uint8_t bcm2835_gpio_lev(uint8_t pin) 253 | { 254 | volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPLEV0/4 + pin/32; 255 | uint8_t shift = pin % 32; 256 | uint32_t value = bcm2835_peri_read(paddr); 257 | return (value & (1 << shift)) ? HIGH : LOW; 258 | } 259 | 260 | /* See if an event detection bit is set 261 | // Sigh cant support interrupts yet 262 | */ 263 | uint8_t bcm2835_gpio_eds(uint8_t pin) 264 | { 265 | volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPEDS0/4 + pin/32; 266 | uint8_t shift = pin % 32; 267 | uint32_t value = bcm2835_peri_read(paddr); 268 | return (value & (1 << shift)) ? HIGH : LOW; 269 | } 270 | 271 | uint32_t bcm2835_gpio_eds_multi(uint32_t mask) 272 | { 273 | volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPEDS0/4; 274 | uint32_t value = bcm2835_peri_read(paddr); 275 | return (value & mask); 276 | } 277 | 278 | /* Write a 1 to clear the bit in EDS */ 279 | void bcm2835_gpio_set_eds(uint8_t pin) 280 | { 281 | volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPEDS0/4 + pin/32; 282 | uint8_t shift = pin % 32; 283 | uint32_t value = 1 << shift; 284 | bcm2835_peri_write(paddr, value); 285 | } 286 | 287 | void bcm2835_gpio_set_eds_multi(uint32_t mask) 288 | { 289 | volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPEDS0/4; 290 | bcm2835_peri_write(paddr, mask); 291 | } 292 | 293 | /* Rising edge detect enable */ 294 | void bcm2835_gpio_ren(uint8_t pin) 295 | { 296 | volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPREN0/4 + pin/32; 297 | uint8_t shift = pin % 32; 298 | uint32_t value = 1 << shift; 299 | bcm2835_peri_set_bits(paddr, value, value); 300 | } 301 | void bcm2835_gpio_clr_ren(uint8_t pin) 302 | { 303 | volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPREN0/4 + pin/32; 304 | uint8_t shift = pin % 32; 305 | uint32_t value = 1 << shift; 306 | bcm2835_peri_set_bits(paddr, 0, value); 307 | } 308 | 309 | /* Falling edge detect enable */ 310 | void bcm2835_gpio_fen(uint8_t pin) 311 | { 312 | volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPFEN0/4 + pin/32; 313 | uint8_t shift = pin % 32; 314 | uint32_t value = 1 << shift; 315 | bcm2835_peri_set_bits(paddr, value, value); 316 | } 317 | void bcm2835_gpio_clr_fen(uint8_t pin) 318 | { 319 | volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPFEN0/4 + pin/32; 320 | uint8_t shift = pin % 32; 321 | uint32_t value = 1 << shift; 322 | bcm2835_peri_set_bits(paddr, 0, value); 323 | } 324 | 325 | /* High detect enable */ 326 | void bcm2835_gpio_hen(uint8_t pin) 327 | { 328 | volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPHEN0/4 + pin/32; 329 | uint8_t shift = pin % 32; 330 | uint32_t value = 1 << shift; 331 | bcm2835_peri_set_bits(paddr, value, value); 332 | } 333 | void bcm2835_gpio_clr_hen(uint8_t pin) 334 | { 335 | volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPHEN0/4 + pin/32; 336 | uint8_t shift = pin % 32; 337 | uint32_t value = 1 << shift; 338 | bcm2835_peri_set_bits(paddr, 0, value); 339 | } 340 | 341 | /* Low detect enable */ 342 | void bcm2835_gpio_len(uint8_t pin) 343 | { 344 | volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPLEN0/4 + pin/32; 345 | uint8_t shift = pin % 32; 346 | uint32_t value = 1 << shift; 347 | bcm2835_peri_set_bits(paddr, value, value); 348 | } 349 | void bcm2835_gpio_clr_len(uint8_t pin) 350 | { 351 | volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPLEN0/4 + pin/32; 352 | uint8_t shift = pin % 32; 353 | uint32_t value = 1 << shift; 354 | bcm2835_peri_set_bits(paddr, 0, value); 355 | } 356 | 357 | /* Async rising edge detect enable */ 358 | void bcm2835_gpio_aren(uint8_t pin) 359 | { 360 | volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPAREN0/4 + pin/32; 361 | uint8_t shift = pin % 32; 362 | uint32_t value = 1 << shift; 363 | bcm2835_peri_set_bits(paddr, value, value); 364 | } 365 | void bcm2835_gpio_clr_aren(uint8_t pin) 366 | { 367 | volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPAREN0/4 + pin/32; 368 | uint8_t shift = pin % 32; 369 | uint32_t value = 1 << shift; 370 | bcm2835_peri_set_bits(paddr, 0, value); 371 | } 372 | 373 | /* Async falling edge detect enable */ 374 | void bcm2835_gpio_afen(uint8_t pin) 375 | { 376 | volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPAFEN0/4 + pin/32; 377 | uint8_t shift = pin % 32; 378 | uint32_t value = 1 << shift; 379 | bcm2835_peri_set_bits(paddr, value, value); 380 | } 381 | void bcm2835_gpio_clr_afen(uint8_t pin) 382 | { 383 | volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPAFEN0/4 + pin/32; 384 | uint8_t shift = pin % 32; 385 | uint32_t value = 1 << shift; 386 | bcm2835_peri_set_bits(paddr, 0, value); 387 | } 388 | 389 | /* Set pullup/down */ 390 | void bcm2835_gpio_pud(uint8_t pud) 391 | { 392 | volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPPUD/4; 393 | bcm2835_peri_write(paddr, pud); 394 | } 395 | 396 | /* Pullup/down clock 397 | // Clocks the value of pud into the GPIO pin 398 | */ 399 | void bcm2835_gpio_pudclk(uint8_t pin, uint8_t on) 400 | { 401 | volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPPUDCLK0/4 + pin/32; 402 | uint8_t shift = pin % 32; 403 | bcm2835_peri_write(paddr, (on ? 1 : 0) << shift); 404 | } 405 | 406 | /* Read GPIO pad behaviour for groups of GPIOs */ 407 | uint32_t bcm2835_gpio_pad(uint8_t group) 408 | { 409 | if (bcm2835_pads == MAP_FAILED) 410 | return 0; 411 | 412 | volatile uint32_t* paddr = bcm2835_pads + BCM2835_PADS_GPIO_0_27/4 + group; 413 | return bcm2835_peri_read(paddr); 414 | } 415 | 416 | /* Set GPIO pad behaviour for groups of GPIOs 417 | // powerup value for all pads is 418 | // BCM2835_PAD_SLEW_RATE_UNLIMITED | BCM2835_PAD_HYSTERESIS_ENABLED | BCM2835_PAD_DRIVE_8mA 419 | */ 420 | void bcm2835_gpio_set_pad(uint8_t group, uint32_t control) 421 | { 422 | if (bcm2835_pads == MAP_FAILED) 423 | return; 424 | 425 | volatile uint32_t* paddr = bcm2835_pads + BCM2835_PADS_GPIO_0_27/4 + group; 426 | bcm2835_peri_write(paddr, control | BCM2835_PAD_PASSWRD); 427 | } 428 | 429 | /* Some convenient arduino-like functions 430 | // milliseconds 431 | */ 432 | void bcm2835_delay(unsigned int millis) 433 | { 434 | struct timespec sleeper; 435 | 436 | sleeper.tv_sec = (time_t)(millis / 1000); 437 | sleeper.tv_nsec = (long)(millis % 1000) * 1000000; 438 | nanosleep(&sleeper, NULL); 439 | } 440 | 441 | /* microseconds */ 442 | void bcm2835_delayMicroseconds(uint64_t micros) 443 | { 444 | struct timespec t1; 445 | uint64_t start; 446 | 447 | if (debug) 448 | { 449 | /* Cant access sytem timers in debug mode */ 450 | printf("bcm2835_delayMicroseconds %lld\n", micros); 451 | return; 452 | } 453 | 454 | /* Calling nanosleep() takes at least 100-200 us, so use it for 455 | // long waits and use a busy wait on the System Timer for the rest. 456 | */ 457 | start = bcm2835_st_read(); 458 | 459 | if (micros > 450) 460 | { 461 | t1.tv_sec = 0; 462 | t1.tv_nsec = 1000 * (long)(micros - 200); 463 | nanosleep(&t1, NULL); 464 | } 465 | 466 | bcm2835_st_delay(start, micros); 467 | } 468 | 469 | /* 470 | // Higher level convenience functions 471 | */ 472 | 473 | /* Set the state of an output */ 474 | void bcm2835_gpio_write(uint8_t pin, uint8_t on) 475 | { 476 | if (on) 477 | bcm2835_gpio_set(pin); 478 | else 479 | bcm2835_gpio_clr(pin); 480 | } 481 | 482 | /* Set the state of a all 32 outputs in the mask to on or off */ 483 | void bcm2835_gpio_write_multi(uint32_t mask, uint8_t on) 484 | { 485 | if (on) 486 | bcm2835_gpio_set_multi(mask); 487 | else 488 | bcm2835_gpio_clr_multi(mask); 489 | } 490 | 491 | /* Set the state of a all 32 outputs in the mask to the values in value */ 492 | void bcm2835_gpio_write_mask(uint32_t value, uint32_t mask) 493 | { 494 | bcm2835_gpio_set_multi(value & mask); 495 | bcm2835_gpio_clr_multi((~value) & mask); 496 | } 497 | 498 | /* Set the pullup/down resistor for a pin 499 | // 500 | // The GPIO Pull-up/down Clock Registers control the actuation of internal pull-downs on 501 | // the respective GPIO pins. These registers must be used in conjunction with the GPPUD 502 | // register to effect GPIO Pull-up/down changes. The following sequence of events is 503 | // required: 504 | // 1. Write to GPPUD to set the required control signal (i.e. Pull-up or Pull-Down or neither 505 | // to remove the current Pull-up/down) 506 | // 2. Wait 150 cycles ? this provides the required set-up time for the control signal 507 | // 3. Write to GPPUDCLK0/1 to clock the control signal into the GPIO pads you wish to 508 | // modify ? NOTE only the pads which receive a clock will be modified, all others will 509 | // retain their previous state. 510 | // 4. Wait 150 cycles ? this provides the required hold time for the control signal 511 | // 5. Write to GPPUD to remove the control signal 512 | // 6. Write to GPPUDCLK0/1 to remove the clock 513 | // 514 | // RPi has P1-03 and P1-05 with 1k8 pullup resistor 515 | */ 516 | void bcm2835_gpio_set_pud(uint8_t pin, uint8_t pud) 517 | { 518 | bcm2835_gpio_pud(pud); 519 | delayMicroseconds(10); 520 | bcm2835_gpio_pudclk(pin, 1); 521 | delayMicroseconds(10); 522 | bcm2835_gpio_pud(BCM2835_GPIO_PUD_OFF); 523 | bcm2835_gpio_pudclk(pin, 0); 524 | } 525 | 526 | int bcm2835_spi_begin(void) 527 | { 528 | volatile uint32_t* paddr; 529 | 530 | if (bcm2835_spi0 == MAP_FAILED) 531 | return 0; /* bcm2835_init() failed, or not root */ 532 | 533 | /* Set the SPI0 pins to the Alt 0 function to enable SPI0 access on them */ 534 | bcm2835_gpio_fsel(RPI_GPIO_P1_26, BCM2835_GPIO_FSEL_ALT0); /* CE1 */ 535 | bcm2835_gpio_fsel(RPI_GPIO_P1_24, BCM2835_GPIO_FSEL_ALT0); /* CE0 */ 536 | bcm2835_gpio_fsel(RPI_GPIO_P1_21, BCM2835_GPIO_FSEL_ALT0); /* MISO */ 537 | bcm2835_gpio_fsel(RPI_GPIO_P1_19, BCM2835_GPIO_FSEL_ALT0); /* MOSI */ 538 | bcm2835_gpio_fsel(RPI_GPIO_P1_23, BCM2835_GPIO_FSEL_ALT0); /* CLK */ 539 | 540 | /* Set the SPI CS register to the some sensible defaults */ 541 | paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; 542 | bcm2835_peri_write(paddr, 0); /* All 0s */ 543 | 544 | /* Clear TX and RX fifos */ 545 | bcm2835_peri_write_nb(paddr, BCM2835_SPI0_CS_CLEAR); 546 | 547 | return 1; // OK 548 | } 549 | 550 | void bcm2835_spi_end(void) 551 | { 552 | /* Set all the SPI0 pins back to input */ 553 | bcm2835_gpio_fsel(RPI_GPIO_P1_26, BCM2835_GPIO_FSEL_INPT); /* CE1 */ 554 | bcm2835_gpio_fsel(RPI_GPIO_P1_24, BCM2835_GPIO_FSEL_INPT); /* CE0 */ 555 | bcm2835_gpio_fsel(RPI_GPIO_P1_21, BCM2835_GPIO_FSEL_INPT); /* MISO */ 556 | bcm2835_gpio_fsel(RPI_GPIO_P1_19, BCM2835_GPIO_FSEL_INPT); /* MOSI */ 557 | bcm2835_gpio_fsel(RPI_GPIO_P1_23, BCM2835_GPIO_FSEL_INPT); /* CLK */ 558 | } 559 | 560 | void bcm2835_spi_setBitOrder(uint8_t __attribute__((unused)) order) 561 | { 562 | /* BCM2835_SPI_BIT_ORDER_MSBFIRST is the only one supported by SPI0 */ 563 | } 564 | 565 | /* defaults to 0, which means a divider of 65536. 566 | // The divisor must be a power of 2. Odd numbers 567 | // rounded down. The maximum SPI clock rate is 568 | // of the APB clock 569 | */ 570 | void bcm2835_spi_setClockDivider(uint16_t divider) 571 | { 572 | volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CLK/4; 573 | bcm2835_peri_write(paddr, divider); 574 | } 575 | 576 | void bcm2835_spi_setDataMode(uint8_t mode) 577 | { 578 | volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; 579 | /* Mask in the CPO and CPHA bits of CS */ 580 | bcm2835_peri_set_bits(paddr, mode << 2, BCM2835_SPI0_CS_CPOL | BCM2835_SPI0_CS_CPHA); 581 | } 582 | 583 | /* Writes (and reads) a single byte to SPI */ 584 | uint8_t bcm2835_spi_transfer(uint8_t value) 585 | { 586 | volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; 587 | volatile uint32_t* fifo = bcm2835_spi0 + BCM2835_SPI0_FIFO/4; 588 | uint32_t ret; 589 | 590 | /* This is Polled transfer as per section 10.6.1 591 | // BUG ALERT: what happens if we get interupted in this section, and someone else 592 | // accesses a different peripheral? 593 | // Clear TX and RX fifos 594 | */ 595 | bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_CLEAR, BCM2835_SPI0_CS_CLEAR); 596 | 597 | /* Set TA = 1 */ 598 | bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_TA, BCM2835_SPI0_CS_TA); 599 | 600 | /* Maybe wait for TXD */ 601 | while (!(bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_TXD)) 602 | ; 603 | 604 | /* Write to FIFO, no barrier */ 605 | bcm2835_peri_write_nb(fifo, value); 606 | 607 | /* Wait for DONE to be set */ 608 | while (!(bcm2835_peri_read_nb(paddr) & BCM2835_SPI0_CS_DONE)) 609 | ; 610 | 611 | /* Read any byte that was sent back by the slave while we sere sending to it */ 612 | ret = bcm2835_peri_read_nb(fifo); 613 | 614 | /* Set TA = 0, and also set the barrier */ 615 | bcm2835_peri_set_bits(paddr, 0, BCM2835_SPI0_CS_TA); 616 | 617 | return ret; 618 | } 619 | 620 | /* Writes (and reads) an number of bytes to SPI */ 621 | void bcm2835_spi_transfernb(char* tbuf, char* rbuf, uint32_t len) 622 | { 623 | volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; 624 | volatile uint32_t* fifo = bcm2835_spi0 + BCM2835_SPI0_FIFO/4; 625 | uint32_t TXCnt=0; 626 | uint32_t RXCnt=0; 627 | 628 | /* This is Polled transfer as per section 10.6.1 629 | // BUG ALERT: what happens if we get interupted in this section, and someone else 630 | // accesses a different peripheral? 631 | */ 632 | 633 | /* Clear TX and RX fifos */ 634 | bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_CLEAR, BCM2835_SPI0_CS_CLEAR); 635 | 636 | /* Set TA = 1 */ 637 | bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_TA, BCM2835_SPI0_CS_TA); 638 | 639 | /* Use the FIFO's to reduce the interbyte times */ 640 | while((TXCnt < len)||(RXCnt < len)) 641 | { 642 | /* TX fifo not full, so add some more bytes */ 643 | while(((bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_TXD))&&(TXCnt < len )) 644 | { 645 | bcm2835_peri_write_nb(fifo, tbuf[TXCnt]); 646 | TXCnt++; 647 | } 648 | /* Rx fifo not empty, so get the next received bytes */ 649 | while(((bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_RXD))&&( RXCnt < len )) 650 | { 651 | rbuf[RXCnt] = bcm2835_peri_read_nb(fifo); 652 | RXCnt++; 653 | } 654 | } 655 | /* Wait for DONE to be set */ 656 | while (!(bcm2835_peri_read_nb(paddr) & BCM2835_SPI0_CS_DONE)) 657 | ; 658 | 659 | /* Set TA = 0, and also set the barrier */ 660 | bcm2835_peri_set_bits(paddr, 0, BCM2835_SPI0_CS_TA); 661 | } 662 | 663 | /* Writes an number of bytes to SPI */ 664 | void bcm2835_spi_writenb(char* tbuf, uint32_t len) 665 | { 666 | volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; 667 | volatile uint32_t* fifo = bcm2835_spi0 + BCM2835_SPI0_FIFO/4; 668 | uint32_t i; 669 | 670 | /* This is Polled transfer as per section 10.6.1 671 | // BUG ALERT: what happens if we get interupted in this section, and someone else 672 | // accesses a different peripheral? 673 | // Answer: an ISR is required to issue the required memory barriers. 674 | */ 675 | 676 | /* Clear TX and RX fifos */ 677 | bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_CLEAR, BCM2835_SPI0_CS_CLEAR); 678 | 679 | /* Set TA = 1 */ 680 | bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_TA, BCM2835_SPI0_CS_TA); 681 | 682 | for (i = 0; i < len; i++) 683 | { 684 | /* Maybe wait for TXD */ 685 | while (!(bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_TXD)) 686 | ; 687 | 688 | /* Write to FIFO, no barrier */ 689 | bcm2835_peri_write_nb(fifo, tbuf[i]); 690 | 691 | /* Read from FIFO to prevent stalling */ 692 | while (bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_RXD) 693 | (void) bcm2835_peri_read_nb(fifo); 694 | } 695 | 696 | /* Wait for DONE to be set */ 697 | while (!(bcm2835_peri_read_nb(paddr) & BCM2835_SPI0_CS_DONE)) { 698 | while (bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_RXD) 699 | (void) bcm2835_peri_read_nb(fifo); 700 | }; 701 | 702 | /* Set TA = 0, and also set the barrier */ 703 | bcm2835_peri_set_bits(paddr, 0, BCM2835_SPI0_CS_TA); 704 | } 705 | 706 | /* Writes (and reads) an number of bytes to SPI 707 | // Read bytes are copied over onto the transmit buffer 708 | */ 709 | void bcm2835_spi_transfern(char* buf, uint32_t len) 710 | { 711 | bcm2835_spi_transfernb(buf, buf, len); 712 | } 713 | 714 | void bcm2835_spi_chipSelect(uint8_t cs) 715 | { 716 | volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; 717 | /* Mask in the CS bits of CS */ 718 | bcm2835_peri_set_bits(paddr, cs, BCM2835_SPI0_CS_CS); 719 | } 720 | 721 | void bcm2835_spi_setChipSelectPolarity(uint8_t cs, uint8_t active) 722 | { 723 | volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; 724 | uint8_t shift = 21 + cs; 725 | /* Mask in the appropriate CSPOLn bit */ 726 | bcm2835_peri_set_bits(paddr, active << shift, 1 << shift); 727 | } 728 | 729 | int bcm2835_i2c_begin(void) 730 | { 731 | uint16_t cdiv; 732 | 733 | if ( bcm2835_bsc0 == MAP_FAILED 734 | || bcm2835_bsc1 == MAP_FAILED) 735 | return 0; /* bcm2835_init() failed, or not root */ 736 | 737 | #ifdef I2C_V1 738 | volatile uint32_t* paddr = bcm2835_bsc0 + BCM2835_BSC_DIV/4; 739 | /* Set the I2C/BSC0 pins to the Alt 0 function to enable I2C access on them */ 740 | bcm2835_gpio_fsel(RPI_GPIO_P1_03, BCM2835_GPIO_FSEL_ALT0); /* SDA */ 741 | bcm2835_gpio_fsel(RPI_GPIO_P1_05, BCM2835_GPIO_FSEL_ALT0); /* SCL */ 742 | #else 743 | volatile uint32_t* paddr = bcm2835_bsc1 + BCM2835_BSC_DIV/4; 744 | /* Set the I2C/BSC1 pins to the Alt 0 function to enable I2C access on them */ 745 | bcm2835_gpio_fsel(RPI_V2_GPIO_P1_03, BCM2835_GPIO_FSEL_ALT0); /* SDA */ 746 | bcm2835_gpio_fsel(RPI_V2_GPIO_P1_05, BCM2835_GPIO_FSEL_ALT0); /* SCL */ 747 | #endif 748 | 749 | /* Read the clock divider register */ 750 | cdiv = bcm2835_peri_read(paddr); 751 | /* Calculate time for transmitting one byte 752 | // 1000000 = micros seconds in a second 753 | // 9 = Clocks per byte : 8 bits + ACK 754 | */ 755 | i2c_byte_wait_us = ((float)cdiv / BCM2835_CORE_CLK_HZ) * 1000000 * 9; 756 | 757 | return 1; 758 | } 759 | 760 | void bcm2835_i2c_end(void) 761 | { 762 | #ifdef I2C_V1 763 | /* Set all the I2C/BSC0 pins back to input */ 764 | bcm2835_gpio_fsel(RPI_GPIO_P1_03, BCM2835_GPIO_FSEL_INPT); /* SDA */ 765 | bcm2835_gpio_fsel(RPI_GPIO_P1_05, BCM2835_GPIO_FSEL_INPT); /* SCL */ 766 | #else 767 | /* Set all the I2C/BSC1 pins back to input */ 768 | bcm2835_gpio_fsel(RPI_V2_GPIO_P1_03, BCM2835_GPIO_FSEL_INPT); /* SDA */ 769 | bcm2835_gpio_fsel(RPI_V2_GPIO_P1_05, BCM2835_GPIO_FSEL_INPT); /* SCL */ 770 | #endif 771 | } 772 | 773 | void bcm2835_i2c_setSlaveAddress(uint8_t addr) 774 | { 775 | /* Set I2C Device Address */ 776 | #ifdef I2C_V1 777 | volatile uint32_t* paddr = bcm2835_bsc0 + BCM2835_BSC_A/4; 778 | #else 779 | volatile uint32_t* paddr = bcm2835_bsc1 + BCM2835_BSC_A/4; 780 | #endif 781 | bcm2835_peri_write(paddr, addr); 782 | } 783 | 784 | /* defaults to 0x5dc, should result in a 166.666 kHz I2C clock frequency. 785 | // The divisor must be a power of 2. Odd numbers 786 | // rounded down. 787 | */ 788 | void bcm2835_i2c_setClockDivider(uint16_t divider) 789 | { 790 | #ifdef I2C_V1 791 | volatile uint32_t* paddr = bcm2835_bsc0 + BCM2835_BSC_DIV/4; 792 | #else 793 | volatile uint32_t* paddr = bcm2835_bsc1 + BCM2835_BSC_DIV/4; 794 | #endif 795 | bcm2835_peri_write(paddr, divider); 796 | /* Calculate time for transmitting one byte 797 | // 1000000 = micros seconds in a second 798 | // 9 = Clocks per byte : 8 bits + ACK 799 | */ 800 | i2c_byte_wait_us = ((float)divider / BCM2835_CORE_CLK_HZ) * 1000000 * 9; 801 | } 802 | 803 | /* set I2C clock divider by means of a baudrate number */ 804 | void bcm2835_i2c_set_baudrate(uint32_t baudrate) 805 | { 806 | uint32_t divider; 807 | /* use 0xFFFE mask to limit a max value and round down any odd number */ 808 | divider = (BCM2835_CORE_CLK_HZ / baudrate) & 0xFFFE; 809 | bcm2835_i2c_setClockDivider( (uint16_t)divider ); 810 | } 811 | 812 | /* Writes an number of bytes to I2C */ 813 | uint8_t bcm2835_i2c_write(const char * buf, uint32_t len) 814 | { 815 | #ifdef I2C_V1 816 | volatile uint32_t* dlen = bcm2835_bsc0 + BCM2835_BSC_DLEN/4; 817 | volatile uint32_t* fifo = bcm2835_bsc0 + BCM2835_BSC_FIFO/4; 818 | volatile uint32_t* status = bcm2835_bsc0 + BCM2835_BSC_S/4; 819 | volatile uint32_t* control = bcm2835_bsc0 + BCM2835_BSC_C/4; 820 | #else 821 | volatile uint32_t* dlen = bcm2835_bsc1 + BCM2835_BSC_DLEN/4; 822 | volatile uint32_t* fifo = bcm2835_bsc1 + BCM2835_BSC_FIFO/4; 823 | volatile uint32_t* status = bcm2835_bsc1 + BCM2835_BSC_S/4; 824 | volatile uint32_t* control = bcm2835_bsc1 + BCM2835_BSC_C/4; 825 | #endif 826 | 827 | uint32_t remaining = len; 828 | uint32_t i = 0; 829 | uint8_t reason = BCM2835_I2C_REASON_OK; 830 | 831 | /* Clear FIFO */ 832 | bcm2835_peri_set_bits(control, BCM2835_BSC_C_CLEAR_1 , BCM2835_BSC_C_CLEAR_1 ); 833 | /* Clear Status */ 834 | bcm2835_peri_write(status, BCM2835_BSC_S_CLKT | BCM2835_BSC_S_ERR | BCM2835_BSC_S_DONE); 835 | /* Set Data Length */ 836 | bcm2835_peri_write(dlen, len); 837 | /* pre populate FIFO with max buffer */ 838 | while( remaining && ( i < BCM2835_BSC_FIFO_SIZE ) ) 839 | { 840 | bcm2835_peri_write_nb(fifo, buf[i]); 841 | i++; 842 | remaining--; 843 | } 844 | 845 | /* Enable device and start transfer */ 846 | bcm2835_peri_write(control, BCM2835_BSC_C_I2CEN | BCM2835_BSC_C_ST); 847 | 848 | /* Transfer is over when BCM2835_BSC_S_DONE */ 849 | while(!(bcm2835_peri_read(status) & BCM2835_BSC_S_DONE )) 850 | { 851 | while ( remaining && (bcm2835_peri_read(status) & BCM2835_BSC_S_TXD )) 852 | { 853 | /* Write to FIFO */ 854 | bcm2835_peri_write(fifo, buf[i]); 855 | i++; 856 | remaining--; 857 | } 858 | } 859 | 860 | /* Received a NACK */ 861 | if (bcm2835_peri_read(status) & BCM2835_BSC_S_ERR) 862 | { 863 | reason = BCM2835_I2C_REASON_ERROR_NACK; 864 | } 865 | 866 | /* Received Clock Stretch Timeout */ 867 | else if (bcm2835_peri_read(status) & BCM2835_BSC_S_CLKT) 868 | { 869 | reason = BCM2835_I2C_REASON_ERROR_CLKT; 870 | } 871 | 872 | /* Not all data is sent */ 873 | else if (remaining) 874 | { 875 | reason = BCM2835_I2C_REASON_ERROR_DATA; 876 | } 877 | 878 | bcm2835_peri_set_bits(control, BCM2835_BSC_S_DONE , BCM2835_BSC_S_DONE); 879 | 880 | return reason; 881 | } 882 | 883 | /* Read an number of bytes from I2C */ 884 | uint8_t bcm2835_i2c_read(char* buf, uint32_t len) 885 | { 886 | #ifdef I2C_V1 887 | volatile uint32_t* dlen = bcm2835_bsc0 + BCM2835_BSC_DLEN/4; 888 | volatile uint32_t* fifo = bcm2835_bsc0 + BCM2835_BSC_FIFO/4; 889 | volatile uint32_t* status = bcm2835_bsc0 + BCM2835_BSC_S/4; 890 | volatile uint32_t* control = bcm2835_bsc0 + BCM2835_BSC_C/4; 891 | #else 892 | volatile uint32_t* dlen = bcm2835_bsc1 + BCM2835_BSC_DLEN/4; 893 | volatile uint32_t* fifo = bcm2835_bsc1 + BCM2835_BSC_FIFO/4; 894 | volatile uint32_t* status = bcm2835_bsc1 + BCM2835_BSC_S/4; 895 | volatile uint32_t* control = bcm2835_bsc1 + BCM2835_BSC_C/4; 896 | #endif 897 | 898 | uint32_t remaining = len; 899 | uint32_t i = 0; 900 | uint8_t reason = BCM2835_I2C_REASON_OK; 901 | 902 | /* Clear FIFO */ 903 | bcm2835_peri_set_bits(control, BCM2835_BSC_C_CLEAR_1 , BCM2835_BSC_C_CLEAR_1 ); 904 | /* Clear Status */ 905 | bcm2835_peri_write_nb(status, BCM2835_BSC_S_CLKT | BCM2835_BSC_S_ERR | BCM2835_BSC_S_DONE); 906 | /* Set Data Length */ 907 | bcm2835_peri_write_nb(dlen, len); 908 | /* Start read */ 909 | bcm2835_peri_write_nb(control, BCM2835_BSC_C_I2CEN | BCM2835_BSC_C_ST | BCM2835_BSC_C_READ); 910 | 911 | /* wait for transfer to complete */ 912 | while (!(bcm2835_peri_read_nb(status) & BCM2835_BSC_S_DONE)) 913 | { 914 | /* we must empty the FIFO as it is populated and not use any delay */ 915 | while (bcm2835_peri_read_nb(status) & BCM2835_BSC_S_RXD) 916 | { 917 | /* Read from FIFO, no barrier */ 918 | buf[i] = bcm2835_peri_read_nb(fifo); 919 | i++; 920 | remaining--; 921 | } 922 | } 923 | 924 | /* transfer has finished - grab any remaining stuff in FIFO */ 925 | while (remaining && (bcm2835_peri_read_nb(status) & BCM2835_BSC_S_RXD)) 926 | { 927 | /* Read from FIFO, no barrier */ 928 | buf[i] = bcm2835_peri_read_nb(fifo); 929 | i++; 930 | remaining--; 931 | } 932 | 933 | /* Received a NACK */ 934 | if (bcm2835_peri_read(status) & BCM2835_BSC_S_ERR) 935 | { 936 | reason = BCM2835_I2C_REASON_ERROR_NACK; 937 | } 938 | 939 | /* Received Clock Stretch Timeout */ 940 | else if (bcm2835_peri_read(status) & BCM2835_BSC_S_CLKT) 941 | { 942 | reason = BCM2835_I2C_REASON_ERROR_CLKT; 943 | } 944 | 945 | /* Not all data is received */ 946 | else if (remaining) 947 | { 948 | reason = BCM2835_I2C_REASON_ERROR_DATA; 949 | } 950 | 951 | bcm2835_peri_set_bits(control, BCM2835_BSC_S_DONE , BCM2835_BSC_S_DONE); 952 | 953 | return reason; 954 | } 955 | 956 | /* Read an number of bytes from I2C sending a repeated start after writing 957 | // the required register. Only works if your device supports this mode 958 | */ 959 | uint8_t bcm2835_i2c_read_register_rs(char* regaddr, char* buf, uint32_t len) 960 | { 961 | #ifdef I2C_V1 962 | volatile uint32_t* dlen = bcm2835_bsc0 + BCM2835_BSC_DLEN/4; 963 | volatile uint32_t* fifo = bcm2835_bsc0 + BCM2835_BSC_FIFO/4; 964 | volatile uint32_t* status = bcm2835_bsc0 + BCM2835_BSC_S/4; 965 | volatile uint32_t* control = bcm2835_bsc0 + BCM2835_BSC_C/4; 966 | #else 967 | volatile uint32_t* dlen = bcm2835_bsc1 + BCM2835_BSC_DLEN/4; 968 | volatile uint32_t* fifo = bcm2835_bsc1 + BCM2835_BSC_FIFO/4; 969 | volatile uint32_t* status = bcm2835_bsc1 + BCM2835_BSC_S/4; 970 | volatile uint32_t* control = bcm2835_bsc1 + BCM2835_BSC_C/4; 971 | #endif 972 | uint32_t remaining = len; 973 | uint32_t i = 0; 974 | uint8_t reason = BCM2835_I2C_REASON_OK; 975 | 976 | /* Clear FIFO */ 977 | bcm2835_peri_set_bits(control, BCM2835_BSC_C_CLEAR_1 , BCM2835_BSC_C_CLEAR_1 ); 978 | /* Clear Status */ 979 | bcm2835_peri_write(status, BCM2835_BSC_S_CLKT | BCM2835_BSC_S_ERR | BCM2835_BSC_S_DONE); 980 | /* Set Data Length */ 981 | bcm2835_peri_write(dlen, 1); 982 | /* Enable device and start transfer */ 983 | bcm2835_peri_write(control, BCM2835_BSC_C_I2CEN); 984 | bcm2835_peri_write(fifo, regaddr[0]); 985 | bcm2835_peri_write(control, BCM2835_BSC_C_I2CEN | BCM2835_BSC_C_ST); 986 | 987 | /* poll for transfer has started */ 988 | while ( !( bcm2835_peri_read(status) & BCM2835_BSC_S_TA ) ) 989 | { 990 | /* Linux may cause us to miss entire transfer stage */ 991 | if(bcm2835_peri_read(status) & BCM2835_BSC_S_DONE) 992 | break; 993 | } 994 | 995 | /* Send a repeated start with read bit set in address */ 996 | bcm2835_peri_write(dlen, len); 997 | bcm2835_peri_write(control, BCM2835_BSC_C_I2CEN | BCM2835_BSC_C_ST | BCM2835_BSC_C_READ ); 998 | 999 | /* Wait for write to complete and first byte back. */ 1000 | bcm2835_delayMicroseconds(i2c_byte_wait_us * 3); 1001 | 1002 | /* wait for transfer to complete */ 1003 | while (!(bcm2835_peri_read(status) & BCM2835_BSC_S_DONE)) 1004 | { 1005 | /* we must empty the FIFO as it is populated and not use any delay */ 1006 | while (remaining && bcm2835_peri_read(status) & BCM2835_BSC_S_RXD) 1007 | { 1008 | /* Read from FIFO */ 1009 | buf[i] = bcm2835_peri_read(fifo); 1010 | i++; 1011 | remaining--; 1012 | } 1013 | } 1014 | 1015 | /* transfer has finished - grab any remaining stuff in FIFO */ 1016 | while (remaining && (bcm2835_peri_read(status) & BCM2835_BSC_S_RXD)) 1017 | { 1018 | /* Read from FIFO */ 1019 | buf[i] = bcm2835_peri_read(fifo); 1020 | i++; 1021 | remaining--; 1022 | } 1023 | 1024 | /* Received a NACK */ 1025 | if (bcm2835_peri_read(status) & BCM2835_BSC_S_ERR) 1026 | { 1027 | reason = BCM2835_I2C_REASON_ERROR_NACK; 1028 | } 1029 | 1030 | /* Received Clock Stretch Timeout */ 1031 | else if (bcm2835_peri_read(status) & BCM2835_BSC_S_CLKT) 1032 | { 1033 | reason = BCM2835_I2C_REASON_ERROR_CLKT; 1034 | } 1035 | 1036 | /* Not all data is sent */ 1037 | else if (remaining) 1038 | { 1039 | reason = BCM2835_I2C_REASON_ERROR_DATA; 1040 | } 1041 | 1042 | bcm2835_peri_set_bits(control, BCM2835_BSC_S_DONE , BCM2835_BSC_S_DONE); 1043 | 1044 | return reason; 1045 | } 1046 | 1047 | /* Sending an arbitrary number of bytes before issuing a repeated start 1048 | // (with no prior stop) and reading a response. Some devices require this behavior. 1049 | */ 1050 | uint8_t bcm2835_i2c_write_read_rs(char* cmds, uint32_t cmds_len, char* buf, uint32_t buf_len) 1051 | { 1052 | #ifdef I2C_V1 1053 | volatile uint32_t* dlen = bcm2835_bsc0 + BCM2835_BSC_DLEN/4; 1054 | volatile uint32_t* fifo = bcm2835_bsc0 + BCM2835_BSC_FIFO/4; 1055 | volatile uint32_t* status = bcm2835_bsc0 + BCM2835_BSC_S/4; 1056 | volatile uint32_t* control = bcm2835_bsc0 + BCM2835_BSC_C/4; 1057 | #else 1058 | volatile uint32_t* dlen = bcm2835_bsc1 + BCM2835_BSC_DLEN/4; 1059 | volatile uint32_t* fifo = bcm2835_bsc1 + BCM2835_BSC_FIFO/4; 1060 | volatile uint32_t* status = bcm2835_bsc1 + BCM2835_BSC_S/4; 1061 | volatile uint32_t* control = bcm2835_bsc1 + BCM2835_BSC_C/4; 1062 | #endif 1063 | 1064 | uint32_t remaining = cmds_len; 1065 | uint32_t i = 0; 1066 | uint8_t reason = BCM2835_I2C_REASON_OK; 1067 | 1068 | /* Clear FIFO */ 1069 | bcm2835_peri_set_bits(control, BCM2835_BSC_C_CLEAR_1 , BCM2835_BSC_C_CLEAR_1 ); 1070 | 1071 | /* Clear Status */ 1072 | bcm2835_peri_write(status, BCM2835_BSC_S_CLKT | BCM2835_BSC_S_ERR | BCM2835_BSC_S_DONE); 1073 | 1074 | /* Set Data Length */ 1075 | bcm2835_peri_write(dlen, cmds_len); 1076 | 1077 | /* pre populate FIFO with max buffer */ 1078 | while( remaining && ( i < BCM2835_BSC_FIFO_SIZE ) ) 1079 | { 1080 | bcm2835_peri_write_nb(fifo, cmds[i]); 1081 | i++; 1082 | remaining--; 1083 | } 1084 | 1085 | /* Enable device and start transfer */ 1086 | bcm2835_peri_write(control, BCM2835_BSC_C_I2CEN | BCM2835_BSC_C_ST); 1087 | 1088 | /* poll for transfer has started (way to do repeated start, from BCM2835 datasheet) */ 1089 | while ( !( bcm2835_peri_read(status) & BCM2835_BSC_S_TA ) ) 1090 | { 1091 | /* Linux may cause us to miss entire transfer stage */ 1092 | if(bcm2835_peri_read_nb(status) & BCM2835_BSC_S_DONE) 1093 | break; 1094 | } 1095 | 1096 | remaining = buf_len; 1097 | i = 0; 1098 | 1099 | /* Send a repeated start with read bit set in address */ 1100 | bcm2835_peri_write(dlen, buf_len); 1101 | bcm2835_peri_write(control, BCM2835_BSC_C_I2CEN | BCM2835_BSC_C_ST | BCM2835_BSC_C_READ ); 1102 | 1103 | /* Wait for write to complete and first byte back. */ 1104 | bcm2835_delayMicroseconds(i2c_byte_wait_us * (cmds_len + 1)); 1105 | 1106 | /* wait for transfer to complete */ 1107 | while (!(bcm2835_peri_read_nb(status) & BCM2835_BSC_S_DONE)) 1108 | { 1109 | /* we must empty the FIFO as it is populated and not use any delay */ 1110 | while (remaining && bcm2835_peri_read(status) & BCM2835_BSC_S_RXD) 1111 | { 1112 | /* Read from FIFO, no barrier */ 1113 | buf[i] = bcm2835_peri_read_nb(fifo); 1114 | i++; 1115 | remaining--; 1116 | } 1117 | } 1118 | 1119 | /* transfer has finished - grab any remaining stuff in FIFO */ 1120 | while (remaining && (bcm2835_peri_read(status) & BCM2835_BSC_S_RXD)) 1121 | { 1122 | /* Read from FIFO */ 1123 | buf[i] = bcm2835_peri_read(fifo); 1124 | i++; 1125 | remaining--; 1126 | } 1127 | 1128 | /* Received a NACK */ 1129 | if (bcm2835_peri_read(status) & BCM2835_BSC_S_ERR) 1130 | { 1131 | reason = BCM2835_I2C_REASON_ERROR_NACK; 1132 | } 1133 | 1134 | /* Received Clock Stretch Timeout */ 1135 | else if (bcm2835_peri_read(status) & BCM2835_BSC_S_CLKT) 1136 | { 1137 | reason = BCM2835_I2C_REASON_ERROR_CLKT; 1138 | } 1139 | 1140 | /* Not all data is sent */ 1141 | else if (remaining) 1142 | { 1143 | reason = BCM2835_I2C_REASON_ERROR_DATA; 1144 | } 1145 | 1146 | bcm2835_peri_set_bits(control, BCM2835_BSC_S_DONE , BCM2835_BSC_S_DONE); 1147 | 1148 | return reason; 1149 | } 1150 | 1151 | /* Read the System Timer Counter (64-bits) */ 1152 | uint64_t bcm2835_st_read(void) 1153 | { 1154 | volatile uint32_t* paddr; 1155 | uint32_t hi, lo; 1156 | uint64_t st; 1157 | paddr = bcm2835_st + BCM2835_ST_CHI/4; 1158 | hi = bcm2835_peri_read(paddr); 1159 | 1160 | paddr = bcm2835_st + BCM2835_ST_CLO/4; 1161 | lo = bcm2835_peri_read(paddr); 1162 | 1163 | paddr = bcm2835_st + BCM2835_ST_CHI/4; 1164 | st = bcm2835_peri_read(paddr); 1165 | 1166 | /* Test for overflow */ 1167 | if (st == hi) 1168 | { 1169 | st <<= 32; 1170 | st += lo; 1171 | } 1172 | else 1173 | { 1174 | st <<= 32; 1175 | paddr = bcm2835_st + BCM2835_ST_CLO/4; 1176 | st += bcm2835_peri_read(paddr); 1177 | } 1178 | return st; 1179 | } 1180 | 1181 | /* Delays for the specified number of microseconds with offset */ 1182 | void bcm2835_st_delay(uint64_t offset_micros, uint64_t micros) 1183 | { 1184 | uint64_t compare = offset_micros + micros; 1185 | 1186 | while(bcm2835_st_read() < compare) 1187 | ; 1188 | } 1189 | 1190 | /* PWM */ 1191 | 1192 | void bcm2835_pwm_set_clock(uint32_t divisor) 1193 | { 1194 | if ( bcm2835_clk == MAP_FAILED 1195 | || bcm2835_pwm == MAP_FAILED) 1196 | return; /* bcm2835_init() failed or not root */ 1197 | 1198 | /* From Gerts code */ 1199 | divisor &= 0xfff; 1200 | /* Stop PWM clock */ 1201 | bcm2835_peri_write(bcm2835_clk + BCM2835_PWMCLK_CNTL, BCM2835_PWM_PASSWRD | 0x01); 1202 | bcm2835_delay(110); /* Prevents clock going slow */ 1203 | /* Wait for the clock to be not busy */ 1204 | while ((bcm2835_peri_read(bcm2835_clk + BCM2835_PWMCLK_CNTL) & 0x80) != 0) 1205 | bcm2835_delay(1); 1206 | /* set the clock divider and enable PWM clock */ 1207 | bcm2835_peri_write(bcm2835_clk + BCM2835_PWMCLK_DIV, BCM2835_PWM_PASSWRD | (divisor << 12)); 1208 | bcm2835_peri_write(bcm2835_clk + BCM2835_PWMCLK_CNTL, BCM2835_PWM_PASSWRD | 0x11); /* Source=osc and enable */ 1209 | } 1210 | 1211 | void bcm2835_pwm_set_mode(uint8_t channel, uint8_t markspace, uint8_t enabled) 1212 | { 1213 | if ( bcm2835_clk == MAP_FAILED 1214 | || bcm2835_pwm == MAP_FAILED) 1215 | return; /* bcm2835_init() failed or not root */ 1216 | 1217 | uint32_t control = bcm2835_peri_read(bcm2835_pwm + BCM2835_PWM_CONTROL); 1218 | 1219 | if (channel == 0) 1220 | { 1221 | if (markspace) 1222 | control |= BCM2835_PWM0_MS_MODE; 1223 | else 1224 | control &= ~BCM2835_PWM0_MS_MODE; 1225 | if (enabled) 1226 | control |= BCM2835_PWM0_ENABLE; 1227 | else 1228 | control &= ~BCM2835_PWM0_ENABLE; 1229 | } 1230 | else if (channel == 1) 1231 | { 1232 | if (markspace) 1233 | control |= BCM2835_PWM1_MS_MODE; 1234 | else 1235 | control &= ~BCM2835_PWM1_MS_MODE; 1236 | if (enabled) 1237 | control |= BCM2835_PWM1_ENABLE; 1238 | else 1239 | control &= ~BCM2835_PWM1_ENABLE; 1240 | } 1241 | 1242 | /* If you use the barrier here, wierd things happen, and the commands dont work */ 1243 | bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM_CONTROL, control); 1244 | /* bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM_CONTROL, BCM2835_PWM0_ENABLE | BCM2835_PWM1_ENABLE | BCM2835_PWM0_MS_MODE | BCM2835_PWM1_MS_MODE); */ 1245 | 1246 | } 1247 | 1248 | void bcm2835_pwm_set_range(uint8_t channel, uint32_t range) 1249 | { 1250 | if ( bcm2835_clk == MAP_FAILED 1251 | || bcm2835_pwm == MAP_FAILED) 1252 | return; /* bcm2835_init() failed or not root */ 1253 | 1254 | if (channel == 0) 1255 | bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM0_RANGE, range); 1256 | else if (channel == 1) 1257 | bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM1_RANGE, range); 1258 | } 1259 | 1260 | void bcm2835_pwm_set_data(uint8_t channel, uint32_t data) 1261 | { 1262 | if ( bcm2835_clk == MAP_FAILED 1263 | || bcm2835_pwm == MAP_FAILED) 1264 | return; /* bcm2835_init() failed or not root */ 1265 | 1266 | if (channel == 0) 1267 | bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM0_DATA, data); 1268 | else if (channel == 1) 1269 | bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM1_DATA, data); 1270 | } 1271 | 1272 | /* Allocate page-aligned memory. */ 1273 | void *malloc_aligned(size_t size) 1274 | { 1275 | void *mem; 1276 | errno = posix_memalign(&mem, BCM2835_PAGE_SIZE, size); 1277 | return (errno ? NULL : mem); 1278 | } 1279 | 1280 | /* Map 'size' bytes starting at 'off' in file 'fd' to memory. 1281 | // Return mapped address on success, MAP_FAILED otherwise. 1282 | // On error print message. 1283 | */ 1284 | static void *mapmem(const char *msg, size_t size, int fd, off_t off) 1285 | { 1286 | void *map = mmap(NULL, size, (PROT_READ | PROT_WRITE), MAP_SHARED, fd, off); 1287 | if (map == MAP_FAILED) 1288 | fprintf(stderr, "bcm2835_init: %s mmap failed: %s\n", msg, strerror(errno)); 1289 | return map; 1290 | } 1291 | 1292 | static void unmapmem(void **pmem, size_t size) 1293 | { 1294 | if (*pmem == MAP_FAILED) return; 1295 | munmap(*pmem, size); 1296 | *pmem = MAP_FAILED; 1297 | } 1298 | 1299 | /* Initialise this library. */ 1300 | int bcm2835_init(void) 1301 | { 1302 | int memfd; 1303 | int ok; 1304 | FILE *fp; 1305 | 1306 | if (debug) 1307 | { 1308 | bcm2835_peripherals = (uint32_t*)BCM2835_PERI_BASE; 1309 | 1310 | bcm2835_pads = bcm2835_peripherals + BCM2835_GPIO_PADS/4; 1311 | bcm2835_clk = bcm2835_peripherals + BCM2835_CLOCK_BASE/4; 1312 | bcm2835_gpio = bcm2835_peripherals + BCM2835_GPIO_BASE/4; 1313 | bcm2835_pwm = bcm2835_peripherals + BCM2835_GPIO_PWM/4; 1314 | bcm2835_spi0 = bcm2835_peripherals + BCM2835_SPI0_BASE/4; 1315 | bcm2835_bsc0 = bcm2835_peripherals + BCM2835_BSC0_BASE/4; 1316 | bcm2835_bsc1 = bcm2835_peripherals + BCM2835_BSC1_BASE/4; 1317 | bcm2835_st = bcm2835_peripherals + BCM2835_ST_BASE/4; 1318 | return 1; /* Success */ 1319 | } 1320 | 1321 | /* Figure out the base and size of the peripheral address block 1322 | // using the device-tree. Required for RPi2, optional for RPi 1 1323 | */ 1324 | if ((fp = fopen(BMC2835_RPI2_DT_FILENAME , "rb"))) 1325 | { 1326 | unsigned char buf[4]; 1327 | fseek(fp, BMC2835_RPI2_DT_PERI_BASE_ADDRESS_OFFSET, SEEK_SET); 1328 | if (fread(buf, 1, sizeof(buf), fp) == sizeof(buf)) 1329 | bcm2835_peripherals_base = (uint32_t *)(buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3] << 0); 1330 | fseek(fp, BMC2835_RPI2_DT_PERI_SIZE_OFFSET, SEEK_SET); 1331 | if (fread(buf, 1, sizeof(buf), fp) == sizeof(buf)) 1332 | bcm2835_peripherals_size = (buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3] << 0); 1333 | fclose(fp); 1334 | } 1335 | /* else we are prob on RPi 1 with BCM2835, and use the hardwired defaults */ 1336 | 1337 | /* Now get ready to map the peripherals block 1338 | * If we are not root, try for the new /dev/gpiomem interface and accept 1339 | * the fact that we can only access GPIO 1340 | * else try for the /dev/mem interface and get access to everything 1341 | */ 1342 | memfd = -1; 1343 | ok = 0; 1344 | if (geteuid() == 0) 1345 | { 1346 | /* Open the master /dev/mem device */ 1347 | if ((memfd = open("/dev/mem", O_RDWR | O_SYNC) ) < 0) 1348 | { 1349 | fprintf(stderr, "bcm2835_init: Unable to open /dev/mem: %s\n", 1350 | strerror(errno)) ; 1351 | goto exit; 1352 | } 1353 | 1354 | /* Base of the peripherals block is mapped to VM */ 1355 | bcm2835_peripherals = mapmem("gpio", bcm2835_peripherals_size, memfd, (uint32_t)bcm2835_peripherals_base); 1356 | if (bcm2835_peripherals == MAP_FAILED) goto exit; 1357 | 1358 | /* Now compute the base addresses of various peripherals, 1359 | // which are at fixed offsets within the mapped peripherals block 1360 | // Caution: bcm2835_peripherals is uint32_t*, so divide offsets by 4 1361 | */ 1362 | bcm2835_gpio = bcm2835_peripherals + BCM2835_GPIO_BASE/4; 1363 | bcm2835_pwm = bcm2835_peripherals + BCM2835_GPIO_PWM/4; 1364 | bcm2835_clk = bcm2835_peripherals + BCM2835_CLOCK_BASE/4; 1365 | bcm2835_pads = bcm2835_peripherals + BCM2835_GPIO_PADS/4; 1366 | bcm2835_spi0 = bcm2835_peripherals + BCM2835_SPI0_BASE/4; 1367 | bcm2835_bsc0 = bcm2835_peripherals + BCM2835_BSC0_BASE/4; /* I2C */ 1368 | bcm2835_bsc1 = bcm2835_peripherals + BCM2835_BSC1_BASE/4; /* I2C */ 1369 | bcm2835_st = bcm2835_peripherals + BCM2835_ST_BASE/4; 1370 | 1371 | ok = 1; 1372 | } 1373 | else 1374 | { 1375 | /* Not root, try /dev/gpiomem */ 1376 | /* Open the master /dev/mem device */ 1377 | if ((memfd = open("/dev/gpiomem", O_RDWR | O_SYNC) ) < 0) 1378 | { 1379 | fprintf(stderr, "bcm2835_init: Unable to open /dev/gpiomem: %s\n", 1380 | strerror(errno)) ; 1381 | goto exit; 1382 | } 1383 | 1384 | /* Base of the peripherals block is mapped to VM */ 1385 | bcm2835_peripherals_base = 0; 1386 | bcm2835_peripherals = mapmem("gpio", bcm2835_peripherals_size, memfd, (uint32_t)bcm2835_peripherals_base); 1387 | if (bcm2835_peripherals == MAP_FAILED) goto exit; 1388 | bcm2835_gpio = bcm2835_peripherals; 1389 | ok = 1; 1390 | } 1391 | 1392 | exit: 1393 | if (memfd >= 0) 1394 | close(memfd); 1395 | 1396 | if (!ok) 1397 | bcm2835_close(); 1398 | 1399 | return ok; 1400 | } 1401 | 1402 | /* Close this library and deallocate everything */ 1403 | int bcm2835_close(void) 1404 | { 1405 | if (debug) return 1; /* Success */ 1406 | 1407 | unmapmem((void**) &bcm2835_peripherals, bcm2835_peripherals_size); 1408 | bcm2835_peripherals = MAP_FAILED; 1409 | bcm2835_gpio = MAP_FAILED; 1410 | bcm2835_pwm = MAP_FAILED; 1411 | bcm2835_clk = MAP_FAILED; 1412 | bcm2835_pads = MAP_FAILED; 1413 | bcm2835_spi0 = MAP_FAILED; 1414 | bcm2835_bsc0 = MAP_FAILED; 1415 | bcm2835_bsc1 = MAP_FAILED; 1416 | bcm2835_st = MAP_FAILED; 1417 | return 1; /* Success */ 1418 | } 1419 | 1420 | #ifdef BCM2835_TEST 1421 | /* this is a simple test program that prints out what it will do rather than 1422 | // actually doing it 1423 | */ 1424 | int main(int argc, char **argv) 1425 | { 1426 | /* Be non-destructive */ 1427 | bcm2835_set_debug(1); 1428 | 1429 | if (!bcm2835_init()) 1430 | return 1; 1431 | 1432 | /* Configure some GPIO pins fo some testing 1433 | // Set RPI pin P1-11 to be an output 1434 | */ 1435 | bcm2835_gpio_fsel(RPI_GPIO_P1_11, BCM2835_GPIO_FSEL_OUTP); 1436 | /* Set RPI pin P1-15 to be an input */ 1437 | bcm2835_gpio_fsel(RPI_GPIO_P1_15, BCM2835_GPIO_FSEL_INPT); 1438 | /* with a pullup */ 1439 | bcm2835_gpio_set_pud(RPI_GPIO_P1_15, BCM2835_GPIO_PUD_UP); 1440 | /* And a low detect enable */ 1441 | bcm2835_gpio_len(RPI_GPIO_P1_15); 1442 | /* and input hysteresis disabled on GPIOs 0 to 27 */ 1443 | bcm2835_gpio_set_pad(BCM2835_PAD_GROUP_GPIO_0_27, BCM2835_PAD_SLEW_RATE_UNLIMITED|BCM2835_PAD_DRIVE_8mA); 1444 | 1445 | #if 1 1446 | /* Blink */ 1447 | while (1) 1448 | { 1449 | /* Turn it on */ 1450 | bcm2835_gpio_write(RPI_GPIO_P1_11, HIGH); 1451 | 1452 | /* wait a bit */ 1453 | bcm2835_delay(500); 1454 | 1455 | /* turn it off */ 1456 | bcm2835_gpio_write(RPI_GPIO_P1_11, LOW); 1457 | 1458 | /* wait a bit */ 1459 | bcm2835_delay(500); 1460 | } 1461 | #endif 1462 | 1463 | #if 0 1464 | /* Read input */ 1465 | while (1) 1466 | { 1467 | /* Read some data */ 1468 | uint8_t value = bcm2835_gpio_lev(RPI_GPIO_P1_15); 1469 | printf("read from pin 15: %d\n", value); 1470 | 1471 | /* wait a bit */ 1472 | bcm2835_delay(500); 1473 | } 1474 | #endif 1475 | 1476 | #if 0 1477 | /* Look for a low event detection 1478 | // eds will be set whenever pin 15 goes low 1479 | */ 1480 | while (1) 1481 | { 1482 | if (bcm2835_gpio_eds(RPI_GPIO_P1_15)) 1483 | { 1484 | /* Now clear the eds flag by setting it to 1 */ 1485 | bcm2835_gpio_set_eds(RPI_GPIO_P1_15); 1486 | printf("low event detect for pin 15\n"); 1487 | } 1488 | 1489 | /* wait a bit */ 1490 | bcm2835_delay(500); 1491 | } 1492 | #endif 1493 | 1494 | if (!bcm2835_close()) 1495 | return 1; 1496 | 1497 | return 0; 1498 | } 1499 | #endif 1500 | 1501 | 1502 | 1503 | --------------------------------------------------------------------------------