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

clockless_arm_stm32.h « stm32 « arm « platforms « src - github.com/FastLED/FastLED.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 0ac8a5d43637778905ce6021632ac30bc295397a (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
#ifndef __INC_CLOCKLESS_ARM_STM32_H
#define __INC_CLOCKLESS_ARM_STM32_H

FASTLED_NAMESPACE_BEGIN
// Definition for a single channel clockless controller for the stm32 family of chips, like that used in the spark core
// See clockless.h for detailed info on how the template parameters are used.

#define FASTLED_HAS_CLOCKLESS 1

template <int DATA_PIN, int T1, int T2, int T3, EOrder RGB_ORDER = RGB, int XTRA0 = 0, bool FLIP = false, int WAIT_TIME = 50>
class ClocklessController : public CPixelLEDController<RGB_ORDER> {
    typedef typename FastPin<DATA_PIN>::port_ptr_t data_ptr_t;
    typedef typename FastPin<DATA_PIN>::port_t data_t;

    data_t mPinMask;
    data_ptr_t mPort;
    CMinWait<WAIT_TIME> mWait;

public:
    virtual void init() {
        FastPin<DATA_PIN>::setOutput();
        mPinMask = FastPin<DATA_PIN>::mask();
        mPort = FastPin<DATA_PIN>::port();
    }

  	virtual uint16_t getMaxRefreshRate() const { return 400; }

protected:
    virtual void showPixels(PixelController<RGB_ORDER> & pixels) {
        mWait.wait();
        if(!showRGBInternal(pixels)) {
            sei(); delayMicroseconds(WAIT_TIME); cli();
            showRGBInternal(pixels);
        }
        mWait.mark();
    }

#define _CYCCNT (*(volatile uint32_t*)(0xE0001004UL))

    template<int BITS> __attribute__ ((always_inline)) inline static void writeBits(register uint32_t & next_mark, register data_ptr_t port, register data_t hi, register data_t lo, register uint8_t & b)  {
        for(register uint32_t i = BITS-1; i > 0; --i) {
            while(_CYCCNT < (T1+T2+T3-20));
            FastPin<DATA_PIN>::fastset(port, hi);
            _CYCCNT = 4;
            if(b&0x80) {
                while(_CYCCNT < (T1+T2-20));
                FastPin<DATA_PIN>::fastset(port, lo);
            } else {
                while(_CYCCNT < (T1-10));
                FastPin<DATA_PIN>::fastset(port, lo);
            }
            b <<= 1;
        }

        while(_CYCCNT < (T1+T2+T3-20));
        FastPin<DATA_PIN>::fastset(port, hi);
        _CYCCNT = 4;

        if(b&0x80) {
            while(_CYCCNT < (T1+T2-20));
            FastPin<DATA_PIN>::fastset(port, lo);
        } else {
            while(_CYCCNT < (T1-10));
            FastPin<DATA_PIN>::fastset(port, lo);
        }
    }

    // This method is made static to force making register Y available to use for data on AVR - if the method is non-static, then
    // gcc will use register Y for the this pointer.
    static uint32_t showRGBInternal(PixelController<RGB_ORDER> pixels) {
        // Get access to the clock
        CoreDebug->DEMCR  |= CoreDebug_DEMCR_TRCENA_Msk;
        DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
        DWT->CYCCNT = 0;

        register data_ptr_t port = FastPin<DATA_PIN>::port();
        register data_t hi = *port | FastPin<DATA_PIN>::mask();;
        register data_t lo = *port & ~FastPin<DATA_PIN>::mask();;
        *port = lo;

        // Setup the pixel controller and load/scale the first byte
        pixels.preStepFirstByteDithering();
        register uint8_t b = pixels.loadAndScale0();

        cli();

        uint32_t next_mark = (T1+T2+T3);

        DWT->CYCCNT = 0;
        while(pixels.has(1)) {
            pixels.stepDithering();
            #if (FASTLED_ALLOW_INTERRUPTS == 1)
            cli();
            // if interrupts took longer than 45µs, punt on the current frame
            if(DWT->CYCCNT > next_mark) {
                if((DWT->CYCCNT-next_mark) > ((WAIT_TIME-INTERRUPT_THRESHOLD)*CLKS_PER_US)) { sei(); return 0; }
            }

            hi = *port | FastPin<DATA_PIN>::mask();
            lo = *port & ~FastPin<DATA_PIN>::mask();
            #endif

            // Write first byte, read next byte
            writeBits<8+XTRA0>(next_mark, port, hi, lo, b);
            b = pixels.loadAndScale1();

            // Write second byte, read 3rd byte
            writeBits<8+XTRA0>(next_mark, port, hi, lo, b);
            b = pixels.loadAndScale2();

            // Write third byte, read 1st byte of next pixel
            writeBits<8+XTRA0>(next_mark, port, hi, lo, b);
            b = pixels.advanceAndLoadAndScale0();
            #if (FASTLED_ALLOW_INTERRUPTS == 1)
            sei();
            #endif
        };

        sei();
        return DWT->CYCCNT;
    }
};

FASTLED_NAMESPACE_END

#endif