2 | Made by Peteris Krumins (about him). His blog is at good coders code, great reuse. Cheers to Reddit folks and the alien!
3 | This site was done in Python and web.py. For more information and source code see the about reddit river page.
4 |
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 |
11 |
12 | $#
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 |
5 |
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 |
5 |
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 |
--------------------------------------------------------------------------------