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.
*
case mOutput:
mode2 = 1;
break;
+ case mSpi:
+ mode2 = GPIO_FSEL_ALT0;
+ break;
default:
break;
}
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.
*
}
}
+/**
+ * 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.
*
enum PinMode {
mUndef,
mOutput,
- mInput
+ mInput,
+ mSpi,
};
/**
* 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:
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)
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:
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
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){
m_pins(),
m_logger(logger),
m_pool(128, logger),
- m_buffers()
+ m_buffers(),
+ m_lastBuffer(-1)
{
memset(m_buffers, 0, sizeof m_buffers);
}
}
}
+/**
+ * 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'.
*
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);
}
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);
Announcer* m_logger;
ThreadPool m_pool;
DynBuffer* m_buffers[26];
+ int m_lastBuffer;
};
#endif // GPIOPROCESSOR_H