]> gitweb.hamatoma.de Git - cpidjinn/commitdiff
implemented: spi transfer
authorhama <hama@siduction.net>
Fri, 24 Jun 2016 23:52:23 +0000 (01:52 +0200)
committerhama <hama@siduction.net>
Fri, 24 Jun 2016 23:52:23 +0000 (01:52 +0200)
Server/bcm2835.cpp
Server/bcm2835.hpp
Server/bcm2835def.hpp
Server/client.cpp
Server/gpioprocessor.cpp
Server/gpioprocessor.hpp

index 9881481d1d5530a66561c874fac29caa92ef7caf..e00ef477381c2aec44f47c889f5537f71b00cde7 100644 (file)
@@ -4,6 +4,16 @@
 
 Bcm2835* Bcm2835::m_instance = NULL;
 
+const int GPIO_FSEL_ALT0 = 0x00;
+const int GPIO_FSEL_ALT1 = 0x05;
+const int GPIO_FSEL_ALT2 = 0x06;
+const int GPIO_FSEL_ALT3 = 0x07;
+const int GPIO_FSEL_ALT4 = 0x03;
+const int GPIO_FSEL_ALT5 = 0x02;
+const int GPIO_FSEL_MASK = 0x07;
+
+const int OFFSET_SPI_CONTROL = 0;
+
 /**
  * Constructor.
  *
@@ -167,6 +177,9 @@ void Bcm2835::setMode(PinNumber pin, PinMode mode)
                case mOutput:
                        mode2 = 1;
                        break;
+               case mSpi:
+                       mode2 = GPIO_FSEL_ALT0;
+                       break;
                default:
                        break;
        }
@@ -221,6 +234,45 @@ void Bcm2835::setInputPullX(PinNumber pin, bool pullUpNotDown){
     writeWord(m_gpioBase + offsetPullXEnableClock0 / sizeof (uint32_t) + pin/32, 0);
 }
 
+/**
+ * Sets a SPI specific parameter.
+ *
+ * @param mode         specify the parameter to change
+ * @param value                the value of the parameter to set
+ * @param value2       2nd value of the parameter to set
+ */
+void Bcm2835::setSpiMode(SpiMode mode, int value, int value2){
+       switch(mode){
+               case spimClockDivider:
+               {
+                       const int OFFSET_SPI_CLOCK = 0x0008;
+                       writeWord(m_spioBase + OFFSET_SPI_CLOCK/4, value);
+                       break;
+               }
+               case spimDataMode:
+               {
+                       // Clock polarity + clock phase:
+                       const int mask = (0x4 | 0x8);
+                       setBits(m_spioBase + OFFSET_SPI_CONTROL/4, value << 2, mask);
+                       break;
+               }
+               case spimChipSelect:
+               {
+                       const int mask = 0x3;
+                       setBits(m_spioBase + OFFSET_SPI_CONTROL/4, value, mask);
+                       break;
+               }
+               case spimChipSelectPolarity:
+               {
+                       int shift = 21 + value;
+                       setBits(m_spioBase + OFFSET_SPI_CONTROL/4, value2 << shift, 1 << shift);
+                       break;
+               }
+               default:
+                       break;
+       }
+}
+
 /**
  * Sets the state of an output pin.
  *
@@ -244,6 +296,86 @@ void Bcm2835::setState(PinNumber pin, PinState state){
        }
 }
 
+/**
+ * Stops a SPI session.
+ */
+void Bcm2835::spiEnd () {
+       // Set pins to input mode:
+       setMode(pinSpiCE1, mInput);
+       setMode(pinSpiCE0, mInput);
+       setMode(pinSpiMISO, mInput);
+       setMode(pinSpiMOSI, mInput);
+       setMode(pinSpiCLK, mInput);
+}
+
+/**
+ * Starts a SPI session.
+ */
+void Bcm2835::spiStart () {
+       setMode(pinSpiCE1, mSpi);
+       setMode(pinSpiCE0, mSpi);
+       setMode(pinSpiMISO, mSpi);
+       setMode(pinSpiMOSI, mSpi);
+       setMode(pinSpiCLK, mSpi);
+
+       const int OFFSET_SPI_CONTROL_STATUS = 0;
+       const int CS_CLEAR = 0x00000030;
+       volatile uint32_t* address = m_spioBase + OFFSET_SPI_CONTROL_STATUS/4;
+    writeWord(address, 0);
+    writeWord(address, CS_CLEAR);
+}
+
+/**
+ * Writes a number of bytes and reads bytes via SPI.
+ *
+ * @param input                        content to send
+ * @param maxOutput            maximal count of bytes to read
+ * @param output               OUT: data read via SPI
+ * @param microseconds 0: busy waiting<br>
+ *                                             otherwise: pause between reads
+*/
+void Bcm2835::spiTransfer(const DynBuffer& input, size_t maxOutput,
+                                                 DynBuffer& output, int microseconds)
+{
+       const int OFFSET_SPI_CONTROL_STATUS = 0;
+       const int OFFSET_FIFO = 4;
+    volatile uint32_t* control = m_spioBase + OFFSET_SPI_CONTROL_STATUS/4;
+    volatile uint32_t* fifo = m_spioBase + OFFSET_FIFO/4;
+    size_t ixInput = 0;
+
+    /* Clear TX and RX fifos, start transfer */
+       const int MASK_CLEAR_TX_RX = 0x30;
+       const int MASK_TRANSFER_ACTIVE = 0x80;
+       const int MASK_TX_FIFO = 0x40000;
+       const int MASK_RX_FIFO = 0x20000;
+       const int MASK_SPI_TRANSFER_DONE = 0x10000;
+
+       setBits(control, MASK_CLEAR_TX_RX, MASK_CLEAR_TX_RX);
+       setBits(control, MASK_TRANSFER_ACTIVE, MASK_TRANSFER_ACTIVE);
+
+    /* Use the FIFO's to reduce the interbyte times */
+    while(ixInput < input.length() || output.length() < maxOutput)
+    {
+               // Fill the sender fifo:
+               while (ixInput < input.length() && (readWord(control) & MASK_TX_FIFO) != 0){
+                       writeWord(fifo, input.at(ixInput++));
+               }
+               // read the receiver fifo:
+               while (output.length() < maxOutput
+                               && (readWord(control) & MASK_RX_FIFO) != 0){
+                               output.append((char) readWord(fifo));
+               }
+               if (microseconds > 0)
+                       delay(microseconds);
+    }
+    // wait for the end of transfer:
+    while( (readWord(control) & MASK_SPI_TRANSFER_DONE) != 0){
+               if (microseconds > 0)
+                       delay(microseconds);
+    }
+    setBits(control, 0, MASK_TRANSFER_ACTIVE);
+}
+
 /**
  * Sets the state of a pin in output mode.
  *
index 9157300f2cb0d0e38403903553eeab6e260f78ab..b10920dfb1f32fbae26896f9abba665dc0bab921 100644 (file)
@@ -8,7 +8,8 @@ enum PinState {
 enum PinMode {
        mUndef,
        mOutput,
-       mInput
+       mInput,
+       mSpi,
 };
 
 /**
@@ -37,6 +38,42 @@ public:
  * This is the heart of the raspberry pi.
  */
 class Bcm2835 {
+public:
+       enum SpiMode {
+               spimUndef,
+               spimClockDivider,
+               spimDataMode,
+               spimChipSelect,
+               spimChipSelectPolarity,
+       };
+       enum SpiValue {
+               spivChipSelect0 = 0,
+               spivChipSelect1 = 1,
+               spivInactive = 0,
+               spivActive = 1,
+               spivLow = 0,
+               spivHigh = 1,
+               spivMode0 = 0,
+               spivMode1 = 1,
+               spivMode2 = 2,
+               spivMode3 = 3,
+               spivDivider2 = 2, //< 125 MHz
+               spivDivider4 = 4, //< 62.5 MHz
+               spivDivider8 = 8, //< 31.25 MHz
+               spivDivider16 = 16, //< 15.6 MHz
+               spivDivider32 = 32, //< 7.8 MHz
+               spivDivider64 = 64, //< 3.9 MHz
+               spivDivider128 = 128, //< 1.9 MHz
+               spivDivider256 = 256, //< 976 kHz
+               spivDivider512 = 512, //< 488 kHz
+               spivDivider1024 = 1024, //< 244 kHz
+               spivDivider2048 = 2048, //< 122 kHz
+               spivDivider4096 = 4096, //< 61 kHz
+               spivDivider8192 = 8192, //< 30.5 kHz
+               spivDivider16384 = 16384, //< 15.2 kHz
+               spivDivider32768 = 32768, //< 7.62 kHz
+               spivDivider65536 = 0, //< 3.81 kHz
+       };
 protected:
     Bcm2835(Announcer* logger, bool simulation = false);
 public:
@@ -52,7 +89,12 @@ public:
        PinState readFromGPIO(PinNumber pin);
        void setInputPullX(PinNumber pin, bool pullUpNotDown);
        void setMode(PinNumber pin, PinMode mode);
+       void setSpiMode(SpiMode, int value, int value2 = 0);
        void setState(PinNumber pin, PinState state);
+       void spiEnd();
+       void spiStart();
+       void spiTransfer(const DynBuffer& input, size_t maxOutput,
+                                                 DynBuffer& output, int microseconds = 0);
        /**
         * Returns whether the instance is valid.
         * @return <i>true</code>: the instance is valid (can work)
@@ -65,6 +107,11 @@ protected:
        uint32_t readWord(volatile uint32_t* addr);
        void setBits(volatile uint32_t* addr, uint32_t value, uint32_t mask);
     void writeWord(volatile uint32_t* addr, uint32_t value);
+       /**
+        */
+       inline void writeWordUnchecked(volatile uint32_t* addr, uint32_t value){
+               *addr = value;
+       }
 private:
        static Bcm2835* m_instance;
 private:
index f618a8e1c98b40f9683b9971da34df047c73b4cc..8fa9221dc9f3947a244f0deda7c40d99f448acfc 100644 (file)
@@ -81,6 +81,12 @@ enum PinNumber {
        pinWiring_14 = 11,
        pinWiring_15 = 14,
        pinWiring_16 = 15,
+
+       pinSpiCE1 = 7,
+       pinSpiCE0 = 8,
+       pinSpiMISO = 9,
+       pinSpiMOSI = 10,
+       pinSpiCLK = 11
 };
 extern PinNumber pinNameToNumber(const char* name);
 #endif // BCM2835DEF_HPP
index 74b92bdb22475fc65e469f1f4ed5156d56c18392..2fe9cd482ced5e91174a6c029f8086230554f5c8 100644 (file)
@@ -178,7 +178,7 @@ int main (int argc, char **argv) {
                if (argc > 3 && (count = toNumber(argv[3], length)) == 0)
                                usage("invalid count", argv[2]);
                int delay = 1000;
-               if (argc > 4 && (count = toNumber(argv[4], length)) == 0)
+               if (argc > 4 && (delay = toNumber(argv[4], length)) == 0)
                                usage("invalid delay", argv[3]);
                prepareTrace(pin, count, delay, buffer);
        } else if (strcmp(command, "getbuffer") == 0){
index e39dfb03f3db76eb5e43a9ccaa5629e28b114f84..43401487e9d3ae5c99c72d6c4484304469bfab9d 100644 (file)
@@ -9,7 +9,8 @@ GPIOProcessor::GPIOProcessor(Announcer* logger, bool simulation) :
        m_pins(),
        m_logger(logger),
        m_pool(128, logger),
-       m_buffers()
+       m_buffers(),
+       m_lastBuffer(-1)
 {
        memset(m_buffers, 0, sizeof m_buffers);
 }
@@ -47,6 +48,29 @@ void GPIOProcessor::blink(DynBuffer& buffer){
        }
 }
 
+/**
+ * Returns the next "free" buffer.
+ *
+ * @param size the size of the buffer
+ * @param name OUT: the name of the buffer
+ * @return             NULL: no free buffer<br>
+ *                             otherwise: a free buffer
+ */
+DynBuffer* GPIOProcessor::findBuffer(int size, char& name){
+       int start;
+       DynBuffer* rc = NULL;
+       if ( (start = ++m_lastBuffer) >= 26)
+               start = m_lastBuffer = 0;
+       for (int ii = 0; ii < 26; ii++){
+               int ix = (start + ii) % 26;
+               if (m_buffers[ix] == NULL){
+                       name = 'A' + ix;
+                       rc = m_buffers[ix] = new DynBuffer(size);
+                       break;
+               }
+       }
+       return rc;
+}
 /**
  * Gets a buffer with data assembled from 'trace'.
  *
@@ -174,19 +198,12 @@ void GPIOProcessor::trace(DynBuffer& buffer){
                int delay = buffer.valueOfLE(4, 4 + 1 + 4);
                printf("Pin: %d count: %d delay: %d\n", pin, count, delay);
                char name = 0;
-               int ix;
-               for (ix = 0; ix < 26; ix++){
-                       if (m_buffers[ix] == NULL){
-                               name = 'A' + ix;
-                               break;
-                       }
-               }
-               if (name == 0){
+               DynBuffer* outputBuffer = findBuffer(count, name);
+               if (outputBuffer == NULL){
                        buffer.set("ERR too few buffers: 26");
                } else {
-                       m_buffers[ix] = new DynBuffer(count);
                        TraceInputTimer* timer = new TraceInputTimer(pin, delay,
-                                               count, m_buffers[ix], this, m_logger, &m_pool);
+                                               count,outputBuffer, this, m_logger, &m_pool);
                        timer->start();
                        buffer.set("OK  #").append(name);
                }
index 9a6bec5d92a891d5077c615c55d5f2c4e5fe7a3d..ac7b3ce6a70ca0f8108908d3f447b130748b98da 100644 (file)
@@ -15,6 +15,7 @@ private:
        GPIOProcessor& operator=(const GPIOProcessor& other);
 private:
        void blink(DynBuffer& buffer);
+       DynBuffer* findBuffer(int size, char& name);
        void getBuffer(DynBuffer& buffer);
        void melody(DynBuffer& buffer);
        void pulseWidthModulation(DynBuffer& buffer);
@@ -26,6 +27,7 @@ private:
        Announcer* m_logger;
        ThreadPool m_pool;
        DynBuffer* m_buffers[26];
+       int m_lastBuffer;
 };
 
 #endif // GPIOPROCESSOR_H