Welcome to mirror list, hosted at ThFree Co, Russian Federation.

fastspi_arm_nrf51.h « nrf51 « arm « platforms « FastLED-master « Библиотеки - github.com/AlexGyver/Arduino_Ambilight.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 539fd65646e2e8c41e63e107db29bdcf5113dfc4 (plain)
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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#ifndef __INC_FASTSPI_NRF_H
#define __INC_FASTSPI_NRF_H

#ifdef NRF51

#ifndef FASTLED_FORCE_SOFTWARE_SPI
#define FASTLED_ALL_PINS_HARDWARE_SPI

// A nop/stub class, mostly to show the SPI methods that are needed/used by the various SPI chipset implementations.  Should
// be used as a definition for the set of methods that the spi implementation classes should use (since C++ doesn't support the
// idea of interfaces - it's possible this could be done with virtual classes, need to decide if i want that overhead)
template <uint8_t _DATA_PIN, uint8_t _CLOCK_PIN, uint8_t _SPI_CLOCK_DIVIDER>
class NRF51SPIOutput {

  struct saveData {
    uint32_t sck;
    uint32_t mosi;
    uint32_t miso;
    uint32_t freq;
    uint32_t enable;
  } mSavedData;

  void saveSPIData() {
    mSavedData.sck = NRF_SPI0->PSELSCK;
    mSavedData.mosi = NRF_SPI0->PSELMOSI;
    mSavedData.miso = NRF_SPI0->PSELMISO;
    mSavedData.freq = NRF_SPI0->FREQUENCY;
    mSavedData.enable = NRF_SPI0->ENABLE;
  }

  void restoreSPIData() {
    NRF_SPI0->PSELSCK = mSavedData.sck;
    NRF_SPI0->PSELMOSI = mSavedData.mosi;
    NRF_SPI0->PSELMISO = mSavedData.miso;
    NRF_SPI0->FREQUENCY = mSavedData.freq;
    mSavedData.enable = NRF_SPI0->ENABLE;
  }

public:
  NRF51SPIOutput() { FastPin<_DATA_PIN>::setOutput(); FastPin<_CLOCK_PIN>::setOutput(); }
  NRF51SPIOutput(Selectable *pSelect) {  FastPin<_DATA_PIN>::setOutput(); FastPin<_CLOCK_PIN>::setOutput();  }

  // set the object representing the selectable
  void setSelect(Selectable *pSelect) { /* TODO */ }

  // initialize the SPI subssytem
  void init() {
    FastPin<_DATA_PIN>::setOutput();
    FastPin<_CLOCK_PIN>::setOutput();
    NRF_SPI0->PSELSCK = _CLOCK_PIN;
    NRF_SPI0->PSELMOSI = _DATA_PIN;
    NRF_SPI0->PSELMISO = 0xFFFFFFFF;
    NRF_SPI0->FREQUENCY = 0x80000000;
    NRF_SPI0->ENABLE = 1;
    NRF_SPI0->EVENTS_READY = 0;
  }

  // latch the CS select
  void select() { saveSPIData(); init(); }

  // release the CS select
  void release() { shouldWait(); restoreSPIData(); }

  static bool shouldWait(bool wait = false) __attribute__((always_inline)) __attribute__((always_inline)) {
    // static bool sWait=false;
    // bool oldWait = sWait;
    // sWait = wait;
    // never going to bother with waiting since we're always running the spi clock at max speed on the rfduino
    // TODO: When we set clock rate, implement/fix waiting properly, otherwise the world hangs up
    return false;
  }
  
  // wait until all queued up data has been written
  static void waitFully() __attribute__((always_inline)){ if(shouldWait()) { while(NRF_SPI0->EVENTS_READY==0); } NRF_SPI0->INTENCLR; }
  static void wait() __attribute__((always_inline)){ if(shouldWait()) { while(NRF_SPI0->EVENTS_READY==0); } NRF_SPI0->INTENCLR; }

  // write a byte out via SPI (returns immediately on writing register)
  static void writeByte(uint8_t b) __attribute__((always_inline)) { wait(); NRF_SPI0->TXD = b; NRF_SPI0->INTENCLR; shouldWait(true); }

  // write a word out via SPI (returns immediately on writing register)
  static void writeWord(uint16_t w) __attribute__((always_inline)){ writeByte(w>>8); writeByte(w & 0xFF);  }

  // A raw set of writing byte values, assumes setup/init/waiting done elsewhere (static for use by adjustment classes)
  static void writeBytesValueRaw(uint8_t value, int len) { while(len--) { writeByte(value);  } }

  // A full cycle of writing a value for len bytes, including select, release, and waiting
  void writeBytesValue(uint8_t value, int len) {
    select();
    while(len--) {
      writeByte(value);
    }
    waitFully();
    release();
  }

  // A full cycle of writing a raw block of data out, including select, release, and waiting
  template<class D> void writeBytes(uint8_t *data, int len) {
    uint8_t *end = data + len;
    select();
    while(data != end) {
      writeByte(D::adjust(*data++));
    }
    D::postBlock(len);
    waitFully();
    release();
  }

  void writeBytes(uint8_t *data, int len) {
    writeBytes<DATA_NOP>(data, len);
  }

  // write a single bit out, which bit from the passed in byte is determined by template parameter
  template <uint8_t BIT> inline static void writeBit(uint8_t b) {
    waitFully();
    NRF_SPI0->ENABLE = 0;
    if(b & 1<<BIT) {
      FastPin<_DATA_PIN>::hi();
    } else {
      FastPin<_DATA_PIN>::lo();
    }
    FastPin<_CLOCK_PIN>::toggle();
    FastPin<_CLOCK_PIN>::toggle();
    NRF_SPI0->ENABLE = 1;
  }

  template <uint8_t FLAGS, class D, EOrder RGB_ORDER> void writePixels(PixelController<RGB_ORDER> pixels) {
    select();
    int len = pixels.mLen;
    while(pixels.has(1)) {
      if(FLAGS & FLAG_START_BIT) {
				writeBit<0>(1);
      }
			writeByte(D::adjust(pixels.loadAndScale0()));
			writeByte(D::adjust(pixels.loadAndScale1()));
			writeByte(D::adjust(pixels.loadAndScale2()));

			pixels.advanceData();
			pixels.stepDithering();
		}
		D::postBlock(len);
		waitFully();
		release();
  }

};

#endif
#endif

#endif