Advertisement
Guest User

ws2812

a guest
Sep 3rd, 2014
252
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // Header File
  2.  
  3. #ifndef WS2812_H_
  4. #define WS2812_H_
  5.  
  6. #include <avr/io.h>
  7. //#include "ml_general.h"
  8.  
  9. //  Constants for timing (common for all arch)
  10.  
  11. #ifndef WS_F_OUT
  12.     #define     WS_F_OUT        800000                  // Output frequency
  13. #endif
  14. #ifndef WS_CNT_TOTAL
  15.     #define     WS_CNT_TOTAL    ((F_CPU/WS_F_OUT)-1)    // # cycles for one bit
  16. #endif
  17. #ifndef WS_CNT_LOW
  18.     #define     WS_CNT_LOW      (((F_CPU/WS_F_OUT)*1)/3-1)  // # cycles for T0H
  19. #endif
  20. #ifndef WS_CNT_HIGH
  21.     #define     WS_CNT_HIGH     (((F_CPU/WS_F_OUT)*2)/3-1) // # cycles for T1H
  22. #endif
  23.  
  24.  
  25. //----- Device specific stuff
  26.  
  27. #define     WS_BUFNUM       6              // Output bytes to buffer
  28. #define     WS_BUFSIZE      (WS_BUFNUM*8)   // required buffer size for this
  29.  
  30. // Port 1
  31. /*
  32.  
  33.  
  34. #define     WS_DMA_A        CH0         // DMA channel A to use
  35. #define     WS_DMA_B        CH1         // DMA channel B to use
  36. #define     WS_DMA_DBUFMODE DMA_DBUFMODE_CH01_gc // DMA DBUFMODE to use
  37. #define     WS_DMA_DBUFMODE_bm DMA_DBUFMODE0_bm
  38. #define     WS_DMA_BUSY_bm  (DMA_CH0BUSY_bm|DMA_CH1BUSY_bm)
  39. #define     WS_DMA_INTLVL   0x02        // Interruptlevel for DMA
  40. #define     WS_TCC          TCD0        // Timer/Counter to use
  41.  
  42. #define     WS_DMA_TRIGSRC  0x01        // TRIGSRC = EVSYS CH0
  43. #define     WS_EVSYS_CH     0           // Eventchannel to use
  44. #define     WS_EVSYS_MUXVAL 0b11010000  // Event selection == TCC0OVF
  45. #define     WS_WGMODE       0x03        // WGMODE_SS
  46. #define     WS_OUTPORT      PORTD       // output port
  47. #define     WS_OUTPIN       0           // output pin
  48. #define     WS_INPIN        4           // input pin (same port)
  49.  
  50. */
  51.  
  52. // Port 1
  53. #define     WS1_BUFNUM       6              // Output bytes to buffer
  54. #define     WS1_BUFSIZE      (WS_BUFNUM*8)   // required buffer size for this
  55.  
  56. #define     WS1_DMA_A       CH0         // DMA channel A to use
  57. #define     WS1_DMA_B       CH1         // DMA channel B to use
  58. #define     WS1_DMA_DBUFMODE DMA_DBUFMODE_CH01_gc // DMA DBUFMODE to use
  59. #define     WS1_DMA_DBUFMODE_bm DMA_DBUFMODE0_bm
  60. #define     WS1_DMA_BUSY_bm  (DMA_CH0BUSY_bm|DMA_CH1BUSY_bm)
  61. #define     WS1_DMA_INTLVL   0x02        // Interruptlevel for DMA
  62. #define     WS1_TCC          TCD0        // Timer/Counter to use
  63.  
  64. #define     WS1_DMA_TRIGSRC  0x01        // TRIGSRC = EVSYS CH0
  65. #define     WS1_EVSYS_CH     0     // Eventchannel to use
  66. #define     WS1_EVSYS_MUXVAL 0b11010000  // Event selection == TCC0OVF
  67. #define     WS1_WGMODE       0x03        // WGMODE_SS
  68. #define     WS1_OUTPORT      PORTD       // output port
  69. #define     WS1_OUTPIN       0           // output pin
  70. #define     WS1_INPIN        4           // input pin (same port)
  71.  
  72. // Port 2
  73. #define     WS2_BUFNUM       6              // Output bytes to buffer
  74. #define     WS2_BUFSIZE      (WS_BUFNUM*8)   // required buffer size for this
  75.  
  76. #define     WS2_DMA_A       CH2         // DMA channel A to use
  77. #define     WS2_DMA_B       CH3         // DMA channel B to use
  78. #define     WS2_DMA_DBUFMODE DMA_DBUFMODE_CH23_gc // DMA DBUFMODE to use
  79. #define     WS2_DMA_DBUFMODE_bm DMA_DBUFMODE0_bm
  80. #define     WS2_DMA_BUSY_bm  (DMA_CH2BUSY_bm|DMA_CH3BUSY_bm)
  81. #define     WS2_DMA_INTLVL   0x02        // Interruptlevel for DMA
  82. #define     WS2_TCC          TCD1        // Timer/Counter to use
  83.  
  84. #define     WS2_DMA_TRIGSRC  0x01        // TRIGSRC = EVSYS CH0
  85. #define     WS2_EVSYS_CH     1     // Eventchannel to use
  86. #define     WS2_EVSYS_MUXVAL 0b11010000  // Event selection == TCC0OVF
  87. #define     WS2_WGMODE       0x03        // WGMODE_SS
  88. #define     WS2_OUTPORT      PORTD       // output port
  89. #define     WS2_OUTPIN       1           // output pin
  90. #define     WS2_INPIN        5           // input pin (same port)
  91.  
  92. //----- Functions
  93.  
  94. #ifndef __ASSEMBLER__
  95.  
  96. //****************************************************************************
  97. //  void WS_init(void)
  98. //
  99. //  DESCR:
  100. //      Initialize hardware
  101. //
  102. //void WS_init(void);
  103. void WS1_init(void);
  104. void WS2_init(void);
  105.  
  106.  
  107. //****************************************************************************
  108. //  uint8_t WS_out(uint8_t *data, uint16_t count, const uint8_t *gamma);
  109. //
  110. //  DESCR:
  111. //      Output bytes to ws2812 leds using fastpwm with gamma correction using
  112. //      the lookup table specified.
  113. //
  114. //      ATTINY+ATMEGA: When gamma is non-null, due to implementation
  115. //      constraints, there is ONE MORE byte read at end of data from memory,
  116. //      but not output.
  117. //
  118. //      XMEGA: If output is already in progress (DMA), this function will
  119. //      return an error.
  120. //
  121. //  IN:
  122. //      r24: uint8_t *data      Ptr. to bytes to output
  123. //      r22: uint16_t count     Number of bytes
  124. //      r20: uint8_t *gamma     Ptr. to GammaTable in FLASH, NULL = none
  125. //
  126. //  OUT:
  127. //      r24: uint8_t status      0=OK, 1=DMA busy
  128. //
  129. //uint8_t WS_out(uint8_t *data, uint16_t count, const uint8_t *gamma);
  130. //uint8_t WS1_out(uint8_t *data, uint16_t count, const uint8_t *gamma);
  131. uint8_t WS1_out(CRGB *data, uint16_t count, const uint8_t *gamma);
  132. uint8_t WS2_out(CRGB *data, uint16_t count, const uint8_t *gamma);
  133. //****************************************************************************
  134. //  uint8_t WS_outCheck(void)
  135. //
  136. //  DESCR
  137. //      Check if output of last data is finished.
  138. //
  139. //  IN:
  140. //
  141. //  OUT:
  142. //      r24: uint8_t status      0=OK, 1=DMA busy
  143. //
  144. //uint8_t WS_outCheck(void);
  145. uint8_t WS1_outCheck(void);
  146. uint8_t WS2_outCheck(void);
  147.  
  148.  
  149. // ASM Source
  150. //****************************************************************************
  151. //  ws2812 - Serial driver for ws2812 RGB leds using fastpwm
  152. //
  153. //  ws2812_xmega - driver for atxmega architecture
  154. //
  155. //  2013 by M. Marquardt (adrock0905@alice.de)
  156. //
  157. //  Please see README.TXT for more information
  158. //
  159.  
  160. //----- Includes
  161.  
  162. #include <avr/io.h>
  163. #include "asmdefs.h"
  164. #include "ws2812.h"
  165.  
  166. //----- Functions
  167. //
  168. //      GCC style parameter register usage:
  169. //      r0: scratch
  170. //      r1: always zero
  171. //      r2-r17, r28-r29: leave unchanged/saved
  172. //      r18-r27, r30-r31: scratch
  173. //      Function arguments - allocated left to right, r25 to r8.
  174. //      All arguments are aligned to start in even-numbered registers
  175. //      (odd-sized arguments, including char, have one free register above
  176. //      them).
  177. //      Return values: 8-bit in r24 (not r25!), 16-bit in r25:r24
  178.  
  179.  
  180. //  Private data struct for DMA mode
  181.  
  182.     STRUCT  WSD
  183.     PTR     WSD_OutPtr                  // Ptr. to output data
  184.     UWORD   WSD_OutCnt                  // Output bytes left
  185.     PTR     WSD_BufAPtr                 // Ptr to Buffer A
  186.     PTR     WSD_BufBPtr                 // Ptr to Buffer B
  187.     PTR     WSD_GammaPtr                // Ptr to gammatable
  188.     UBYTE   WSD_EndFlag                 // Flag for end
  189.     UBYTE   WSD_Fill
  190.     LABEL   WSD_SizeOf
  191.  
  192.     STRUCT  WSD2
  193.     PTR     WSD2_OutPtr                  // Ptr. to output data
  194.     UWORD   WSD2_OutCnt                  // Output bytes left
  195.     PTR     WSD2_BufAPtr                 // Ptr to Buffer A
  196.     PTR     WSD2_BufBPtr                 // Ptr to Buffer B
  197.     PTR     WSD2_GammaPtr                // Ptr to gammatable
  198.     UBYTE   WSD2_EndFlag                 // Flag for end
  199.     UBYTE   WSD2_Fill
  200.     LABEL   WSD2_SizeOf
  201.    
  202. // Some brain-twisting macros used in asm source
  203.  
  204. #define     WS_DMA(CH, REG) WS_DMA_(WS1_DMA_ ## CH, REG)
  205. #define     WS_DMA_(CH, REG) WS_DMA__(CH, REG)
  206. #define     WS_DMA__(CH, REG) DMA_ ## CH ## _ ## REG
  207. #define     WS_DMA_R(CH, REG) WS_DMA(CH, REG)-WS_DMA(CH, CTRLA)
  208. #define     WS_TC(TCC, REG) WS_TC_(TCC, REG)
  209. #define     WS_TC_(TCC, REG) TCC ## _ ## REG
  210. #define     WS_TC_R(TCC, REG) WS_TC(TCC, REG)-WS_TC(TCC, CTRLA)
  211. #define     WS_PORT(PORT, REG) WS_PORT_(PORT, REG)
  212. #define     WS_PORT_(PORT, REG) PORT ## _ ## REG
  213. #define     WS_ENDBYTE  0xff
  214. #define     WS_MERGE(A, B, C) WS_MERGE_(A, B, C)
  215. #define     WS_MERGE_(A, B, C) A ## B ## C
  216.  
  217. #define     WS2_DMA(CH, REG) WS2_DMA_(WS2_DMA_ ## CH, REG)
  218. #define     WS2_DMA_(CH, REG) WS2_DMA__(CH, REG)
  219. #define     WS2_DMA__(CH, REG) DMA_ ## CH ## _ ## REG
  220. #define     WS2_DMA_R(CH, REG) WS2_DMA(CH, REG)-WS2_DMA(CH, CTRLA)
  221. #define     WS2_TC(TCC, REG) WS2_TC_(TCC, REG)
  222. #define     WS2_TC_(TCC, REG) TCC ## _ ## REG
  223. #define     WS2_TC_R(TCC, REG) WS2_TC(TCC, REG)-WS2_TC(TCC, CTRLA)
  224. #define     WS2_PORT(PORT, REG) WS2_PORT_(PORT, REG)
  225. #define     WS2_PORT_(PORT, REG) PORT ## _ ## REG
  226. #define     WS2_ENDBYTE  0xff
  227. #define     WS2_MERGE(A, B, C) WS2_MERGE_(A, B, C)
  228. #define     WS2_MERGE_(A, B, C) A ## B ## C
  229.  
  230. #define     WS1_EVSYS_MUX    WS_MERGE(EVSYS_CH, WS1_EVSYS_CH, MUX) // EVSYS mux to use (CH0)
  231. #define     WS1_EVSYS_CTRL   WS_MERGE(EVSYS_CH, WS1_EVSYS_CH, CTRL) // EVSYS ctrl to use (Ch0)
  232. #define     WS2_EVSYS_MUX    WS_MERGE(EVSYS_CH, WS2_EVSYS_CH, MUX) // EVSYS mux to use (CH0)
  233. #define     WS2_EVSYS_CTRL   WS_MERGE(EVSYS_CH, WS2_EVSYS_CH, CTRL) // EVSYS ctrl to use (Ch0)
  234.  
  235.  
  236.  
  237. //****************************************************************************
  238. //  void WS1_init(void)
  239. //
  240. //  DESCR:
  241. //      Initialize hardware
  242. //
  243. //  SCRATCH:
  244. //      r24, r25, r26, r27, r30, r31
  245. //
  246. .global WS1_init
  247.  
  248. WS1_init:
  249.     push    r28
  250.     push    r29
  251.  
  252.     clr     r26
  253.  
  254.     // Initialize internal data structure
  255.  
  256.     ldi     r30, lo8(WSData)            // Z = Ptr. to internal data
  257.     ldi     r31, hi8(WSData)
  258.  
  259.     ldi     r24, lo8(WS_BufferA)        // init. BufAPtr
  260.     std     Z+WSD_BufAPtr, r24
  261.     ldi     r24, hi8(WS_BufferA)
  262.     std     Z+WSD_BufAPtr+1, r24
  263.  
  264.     ldi     r24, lo8(WS_BufferB)        // init. BufBPtr
  265.     std     Z+WSD_BufBPtr, r24
  266.     ldi     r24, hi8(WS_BufferB)
  267.     std     Z+WSD_BufBPtr+1, r24
  268.  
  269.     // Init IO port
  270.  
  271.     ldi     r24, _BV(WS1_OUTPIN)
  272.     sts     WS_MERGE(WS1_OUTPORT, _OUTCLR,), r24 // Set output low
  273.     sts     WS_MERGE(WS1_OUTPORT, _DIRSET,), r24 // Set DDR for output
  274.  
  275.     // Initialize DMA stuff
  276.  
  277.     lds     r24, DMA_CTRL
  278.     ori     r24, DMA_ENABLE_bm|WS1_DMA_DBUFMODE_bm
  279.     sts     DMA_CTRL, r24
  280.  
  281.     ldi     r28, lo8(WS_DMA(A, CTRLA))  // Y = DMA ch A BASE
  282.     ldi     r29, hi8(WS_DMA(A, CTRLA))
  283.     ldi     r30, lo8(WS_DMA(B, CTRLA))  // Z = DMA ch B BASE
  284.     ldi     r31, hi8(WS_DMA(B, CTRLA))
  285.  
  286.     ldi     r24, DMA_CH_SINGLE_bm|DMA_CH_REPEAT_bm|(0x00<<DMA_CH_BURSTLEN_gp)
  287.     std     Y+WS_DMA_R(A, CTRLA), r24
  288.     std     Z+WS_DMA_R(B, CTRLA), r24
  289.  
  290.     ldi     r24, WS1_DMA_INTLVL<<DMA_CH_TRNINTLVL_gp
  291.     std     Y+WS_DMA_R(A, CTRLB), r24
  292.     std     Z+WS_DMA_R(B, CTRLB), r24
  293.  
  294.     ldi     r24, DMA_CH_SRCRELOAD0_bm|DMA_CH_SRCRELOAD1_bm|DMA_CH_SRCDIR0_bm
  295.     std     Y+WS_DMA_R(A, ADDRCTRL), r24
  296.     std     Z+WS_DMA_R(B, ADDRCTRL), r24
  297.  
  298.     ldi     r24, WS1_DMA_TRIGSRC<<DMA_CH_TRIGSRC_gp
  299.     std     Y+WS_DMA_R(A, TRIGSRC), r24
  300.     std     Z+WS_DMA_R(B, TRIGSRC), r24
  301.  
  302.     std     Y+WS_DMA_R(A, REPCNT), r26
  303.     std     Y+WS_DMA_R(A, REPCNT+1), r26
  304.     std     Z+WS_DMA_R(B, REPCNT), r26
  305.     std     Z+WS_DMA_R(B, REPCNT+1), r26
  306.  
  307.     ldi     r24, lo8(WS_BufferA)
  308.     ldi     r25, hi8(WS_BufferA)
  309.     std     Y+WS_DMA_R(A, SRCADDR0), r24
  310.     std     Y+WS_DMA_R(A, SRCADDR1), r25
  311.     std     Y+WS_DMA_R(A, SRCADDR2), r26
  312.  
  313.     ldi     r24, lo8(WS_BufferB)
  314.     ldi     r25, hi8(WS_BufferB)
  315.     std     Z+WS_DMA_R(B, SRCADDR0), r24
  316.     std     Z+WS_DMA_R(B, SRCADDR1), r25
  317.     std     Z+WS_DMA_R(B, SRCADDR2), r26
  318.  
  319.     ldi     r24, (WS_TC(WS1_TCC, CCABUF))&0xff
  320.     ldi     r25, (WS_TC(WS1_TCC, CCABUF))>>8
  321.     std     Y+WS_DMA_R(A, DESTADDR0), r24
  322.     std     Y+WS_DMA_R(A, DESTADDR1), r25
  323.     std     Y+WS_DMA_R(A, DESTADDR2), r26
  324.     std     Z+WS_DMA_R(B, DESTADDR0), r24
  325.     std     Z+WS_DMA_R(B, DESTADDR1), r25
  326.     std     Z+WS_DMA_R(B, DESTADDR2), r26
  327.  
  328.     // Init event system to trigger DMA transfer for each timer overflow
  329.  
  330.     ldi     r24, WS1_EVSYS_MUXVAL
  331.     sts     WS1_EVSYS_MUX, r24
  332.     sts     WS1_EVSYS_CTRL, r26
  333.  
  334.     // Init timer stuff
  335.  
  336.     ldi     r30, lo8(WS_TC(WS1_TCC, CTRLA))  // Z = TCx base
  337.     ldi     r31, hi8(WS_TC(WS1_TCC, CTRLB))
  338.  
  339.     ldi     r24, TC0_CCAEN_bm|(WS1_WGMODE<<TC0_WGMODE_gp) // enable timer
  340.     std     Z+WS_TC_R(WS1_TCC, CTRLB), r24
  341.     std     Z+WS_TC_R(WS1_TCC, CTRLC), r26
  342.  
  343.     ldi     r24, TC0_BYTEM_bm
  344.     std     Z+WS_TC_R(WS1_TCC, CTRLE), r24
  345.  
  346.     ldi     r24, WS_CNT_TOTAL
  347.     std     Z+WS_TC_R(WS1_TCC, PERBUF), r24
  348.     std     Z+WS_TC_R(WS1_TCC, PERBUF+1), r26
  349.     std     Z+WS_TC_R(WS1_TCC, PER), r24
  350.     std     Z+WS_TC_R(WS1_TCC, PER+1), r26
  351.  
  352.     pop     r29
  353.     pop     r28
  354.     ret
  355.  
  356. //****************************************************************************
  357. //  void WS2_init(void)
  358. //
  359. //  DESCR:
  360. //      Initialize hardware
  361. //
  362. //  SCRATCH:
  363. //      r24, r25, r26, r27, r30, r31
  364. //
  365. .global WS1_init
  366.  
  367. WS2_init:
  368.     push    r28
  369.     push    r29
  370.  
  371.     clr     r26
  372.  
  373.     // Initialize internal data structure
  374.  
  375.     ldi     r30, lo8(WS2Data)            // Z = Ptr. to internal data
  376.     ldi     r31, hi8(WS2Data)
  377.  
  378.     ldi     r24, lo8(WS2_BufferA)        // init. BufAPtr
  379.     std     Z+WSD2_BufAPtr, r24
  380.     ldi     r24, hi8(WS2_BufferA)
  381.     std     Z+WSD2_BufAPtr+1, r24
  382.  
  383.     ldi     r24, lo8(WS2_BufferB)        // init. BufBPtr
  384.     std     Z+WSD2_BufBPtr, r24
  385.     ldi     r24, hi8(WS2_BufferB)
  386.     std     Z+WSD2_BufBPtr+1, r24
  387.  
  388.     // Init IO port
  389.  
  390.     ldi     r24, _BV(WS2_OUTPIN)
  391.     sts     WS_MERGE(WS2_OUTPORT, _OUTCLR,), r24 // Set output low
  392.     sts     WS_MERGE(WS2_OUTPORT, _DIRSET,), r24 // Set DDR for output
  393.  
  394.     // Initialize DMA stuff
  395.  
  396.     lds     r24, DMA_CTRL
  397.     ori     r24, DMA_ENABLE_bm|WS2_DMA_DBUFMODE_bm
  398.     sts     DMA_CTRL, r24
  399.  
  400.     ldi     r28, lo8(WS2_DMA(A, CTRLA))  // Y = DMA ch A BASE
  401.     ldi     r29, hi8(WS2_DMA(A, CTRLA))
  402.     ldi     r30, lo8(WS2_DMA(B, CTRLA))  // Z = DMA ch B BASE
  403.     ldi     r31, hi8(WS2_DMA(B, CTRLA))
  404.  
  405.     ldi     r24, DMA_CH_SINGLE_bm|DMA_CH_REPEAT_bm|(0x00<<DMA_CH_BURSTLEN_gp)
  406.     std     Y+WS2_DMA_R(A, CTRLA), r24
  407.     std     Z+WS2_DMA_R(B, CTRLA), r24
  408.  
  409.     ldi     r24, WS2_DMA_INTLVL<<DMA_CH_TRNINTLVL_gp
  410.     std     Y+WS2_DMA_R(A, CTRLB), r24
  411.     std     Z+WS2_DMA_R(B, CTRLB), r24
  412.  
  413.     ldi     r24, DMA_CH_SRCRELOAD0_bm|DMA_CH_SRCRELOAD1_bm|DMA_CH_SRCDIR0_bm
  414.     std     Y+WS2_DMA_R(A, ADDRCTRL), r24
  415.     std     Z+WS2_DMA_R(B, ADDRCTRL), r24
  416.  
  417.     ldi     r24, WS2_DMA_TRIGSRC<<DMA_CH_TRIGSRC_gp
  418.     std     Y+WS2_DMA_R(A, TRIGSRC), r24
  419.     std     Z+WS2_DMA_R(B, TRIGSRC), r24
  420.  
  421.     std     Y+WS2_DMA_R(A, REPCNT), r26
  422.     std     Y+WS2_DMA_R(A, REPCNT+1), r26
  423.     std     Z+WS2_DMA_R(B, REPCNT), r26
  424.     std     Z+WS2_DMA_R(B, REPCNT+1), r26
  425.  
  426.     ldi     r24, lo8(WS2_BufferA)
  427.     ldi     r25, hi8(WS2_BufferA)
  428.     std     Y+WS2_DMA_R(A, SRCADDR0), r24
  429.     std     Y+WS2_DMA_R(A, SRCADDR1), r25
  430.     std     Y+WS2_DMA_R(A, SRCADDR2), r26
  431.  
  432.     ldi     r24, lo8(WS2_BufferB)
  433.     ldi     r25, hi8(WS2_BufferB)
  434.     std     Z+WS2_DMA_R(B, SRCADDR0), r24
  435.     std     Z+WS2_DMA_R(B, SRCADDR1), r25
  436.     std     Z+WS2_DMA_R(B, SRCADDR2), r26
  437.  
  438.     ldi     r24, (WS2_TC(WS2_TCC, CCABUF))&0xff
  439.     ldi     r25, (WS2_TC(WS2_TCC, CCABUF))>>8
  440.     std     Y+WS2_DMA_R(A, DESTADDR0), r24
  441.     std     Y+WS2_DMA_R(A, DESTADDR1), r25
  442.     std     Y+WS2_DMA_R(A, DESTADDR2), r26
  443.     std     Z+WS2_DMA_R(B, DESTADDR0), r24
  444.     std     Z+WS2_DMA_R(B, DESTADDR1), r25
  445.     std     Z+WS2_DMA_R(B, DESTADDR2), r26
  446.  
  447.     // Init event system to trigger DMA transfer for each timer overflow
  448.  
  449.     ldi     r24, WS2_EVSYS_MUXVAL
  450.     sts     WS2_EVSYS_MUX, r24
  451.     sts     WS2_EVSYS_CTRL, r26
  452.  
  453.     // Init timer stuff
  454.  
  455.     ldi     r30, lo8(WS2_TC(WS2_TCC, CTRLA))  // Z = TCx base
  456.     ldi     r31, hi8(WS2_TC(WS2_TCC, CTRLB))
  457.  
  458.     ldi     r24, TC0_CCAEN_bm|(WS2_WGMODE<<TC0_WGMODE_gp) // enable timer
  459.     std     Z+WS2_TC_R(WS2_TCC, CTRLB), r24
  460.     std     Z+WS2_TC_R(WS2_TCC, CTRLC), r26
  461.  
  462.     ldi     r24, TC0_BYTEM_bm
  463.     std     Z+WS2_TC_R(WS2_TCC, CTRLE), r24
  464.  
  465.     ldi     r24, WS_CNT_TOTAL
  466.     std     Z+WS2_TC_R(WS2_TCC, PERBUF), r24
  467.     std     Z+WS2_TC_R(WS2_TCC, PERBUF+1), r26
  468.     std     Z+WS2_TC_R(WS2_TCC, PER), r24
  469.     std     Z+WS2_TC_R(WS2_TCC, PER+1), r26
  470.  
  471.     pop     r29
  472.     pop     r28
  473.     ret
  474.  
  475.  
  476.  
  477. //****************************************************************************
  478. //      uint8_t WS_out(uint8_t *data, uint16_t count, const uint8_t *gamma);
  479. //
  480. //  DESCR:
  481. //      Output bytes to ws2812 leds using fastpwm with gamma correction using
  482. //      the lookup table specified.
  483. //
  484. //      If output is already in progress (DMA), this function will
  485. //      return an error.
  486. //
  487. //  IN:
  488. //      r24: uint8_t *data      Ptr. to bytes to output
  489. //      r22: uint16_t count     Number of bytes
  490. //      r20: uint8_t *gamma     Ptr. to GammaTable in FLASH, NULL = none
  491. //
  492. //  OUT:
  493. //      r24: uint8_t status      0=OK, 1: DMA Busy
  494. //
  495. //  SCRATCH:
  496. //      r0, r18, r19, r20, r21, r22/r23, r24/r25, r26/r27, r30/r31
  497. //
  498. .global WS1_out
  499.  
  500. WS1_out:
  501.     push    r28
  502.     push    r29
  503.  
  504.     lds     r18, DMA_STATUS             // check if DMA is still in progress
  505.     andi    r18, WS1_DMA_BUSY_bm
  506.     breq    WS1_out_notbusy              // zero -> no active DMA
  507.  
  508.     ldi     r24, 1                      // ret = 1 (busy)
  509.     rjmp    WS1_out0
  510.  
  511. WS1_out_notbusy:
  512.  
  513.     // Fill internal structure with data
  514.  
  515.     ldi     r30, lo8(WSData)
  516.     ldi     r31, hi8(WSData)
  517.  
  518.     std     Z+WSD_OutPtr, r24
  519.     std     Z+WSD_OutPtr+1, r25
  520.     std     Z+WSD_OutCnt, r22
  521.     std     Z+WSD_OutCnt+1, r23
  522.     std     Z+WSD_GammaPtr, r20
  523.     std     Z+WSD_GammaPtr+1, r21
  524.     std     Z+WSD_EndFlag, r1
  525.  
  526.     // Initially disable repeat mode for DMA channel A+B
  527.  
  528.     lds     r24, WS_DMA(A, CTRLA)       // disable repeat for channel A
  529.     andi    r24, ~DMA_CH_REPEAT_bm
  530.     sts     WS_DMA(A, CTRLA), r24
  531.  
  532.     lds     r24, WS_DMA(B, CTRLA)       // disable repeat for channel B
  533.     andi    r24, ~DMA_CH_REPEAT_bm
  534.     sts     WS_DMA(B, CTRLA), r24
  535.  
  536.     // At beginning, fill both buffers with data
  537.  
  538.     clr     r24                         // Buffer 0
  539.     rcall   WS1_WriteBuf
  540.  
  541.     sts     WS_DMA(A, TRFCNT), r24      // set number of bytes for DMA
  542.     sts     WS_DMA(A, TRFCNT+1), r25
  543.  
  544.     ldd     r24, Z+WSD_EndFlag
  545.     tst     r24                         // already end?
  546.     brne    WS1_out_start                // yes!
  547.  
  548.     lds     r24, WS_DMA(B, CTRLA)       // enable repeat for channel B
  549.     ori     r24, DMA_CH_REPEAT_bm
  550.     sts     WS_DMA(B, CTRLA), r24
  551.  
  552.     ldi     r24, 1                      // Buffer 1
  553.     rcall   WS1_WriteBuf
  554.  
  555.     sts     WS_DMA(B, TRFCNT), r24      // set number of byes for DMA
  556.     sts     WS_DMA(B, TRFCNT+1), r25
  557.  
  558.     ldd     r24, Z+WSD_EndFlag
  559.     tst     r24                         // already end?
  560.     brne    WS1_out_start                // yes!
  561.  
  562.     lds     r24, WS_DMA(A, CTRLA)       // enable repeat for channel A
  563.     ori     r24, DMA_CH_REPEAT_bm
  564.     sts     WS_DMA(A, CTRLA), r24
  565.  
  566.     // Enable DMA and start counter
  567.  
  568. WS1_out_start:
  569.     ldi     r24, 1
  570.     sts     WS_TC(WS1_TCC, CNT), r24     // Init counter with 1 to avoid HIGH state on first run
  571.     sts     WS_TC(WS1_TCC, CCA), r1
  572.  
  573.     lds     r24, WS_DMA(A, CTRLA)       // Enable DMA channel A
  574.     ori     r24, DMA_CH_ENABLE_bm
  575.     sts     WS_DMA(A, CTRLA), r24
  576.  
  577.     ldi     r24, (0x01<<TC0_CLKSEL_gp)  // Start timer
  578.     sts     WS_TC(WS1_TCC, CTRLA), r24
  579.  
  580.     ldi     r24, 1<<WS1_EVSYS_CH         // STROBE EVSYS
  581.     sts     EVSYS_STROBE, r24
  582.  
  583.     clr     r24
  584.  
  585. WS1_out0:
  586.     pop     r29
  587.     pop     r28
  588.     ret
  589.  
  590. //****************************************************************************
  591. //      uint8_t WS2_out(uint8_t *data, uint16_t count, const uint8_t *gamma);
  592. //
  593. //  DESCR:
  594. //      Output bytes to ws2812 leds using fastpwm with gamma correction using
  595. //      the lookup table specified.
  596. //
  597. //      If output is already in progress (DMA), this function will
  598. //      return an error.
  599. //
  600. //  IN:
  601. //      r24: uint8_t *data      Ptr. to bytes to output
  602. //      r22: uint16_t count     Number of bytes
  603. //      r20: uint8_t *gamma     Ptr. to GammaTable in FLASH, NULL = none
  604. //
  605. //  OUT:
  606. //      r24: uint8_t status      0=OK, 1: DMA Busy
  607. //
  608. //  SCRATCH:
  609. //      r0, r18, r19, r20, r21, r22/r23, r24/r25, r26/r27, r30/r31
  610. //
  611. .global WS2_out
  612.  
  613. WS2_out:
  614.     push    r28
  615.     push    r29
  616.  
  617.     lds     r18, DMA_STATUS             // check if DMA is still in progress
  618.     andi    r18, WS2_DMA_BUSY_bm
  619.     breq    WS2_out_notbusy              // zero -> no active DMA
  620.  
  621.     ldi     r24, 1                      // ret = 1 (busy)
  622.     rjmp    WS2_out0
  623.  
  624. WS2_out_notbusy:
  625.  
  626.     // Fill internal structure with data
  627.  
  628.     ldi     r30, lo8(WS2Data)
  629.     ldi     r31, hi8(WS2Data)
  630.  
  631.     std     Z+WSD2_OutPtr, r24
  632.     std     Z+WSD2_OutPtr+1, r25
  633.     std     Z+WSD2_OutCnt, r22
  634.     std     Z+WSD2_OutCnt+1, r23
  635.     std     Z+WSD2_GammaPtr, r20
  636.     std     Z+WSD2_GammaPtr+1, r21
  637.     std     Z+WSD2_EndFlag, r1
  638.  
  639.     // Initially disable repeat mode for DMA channel A+B
  640.  
  641.     lds     r24, WS2_DMA(A, CTRLA)       // disable repeat for channel A
  642.     andi    r24, ~DMA_CH_REPEAT_bm
  643.     sts     WS2_DMA(A, CTRLA), r24
  644.  
  645.     lds     r24, WS2_DMA(B, CTRLA)       // disable repeat for channel B
  646.     andi    r24, ~DMA_CH_REPEAT_bm
  647.     sts     WS2_DMA(B, CTRLA), r24
  648.  
  649.     // At beginning, fill both buffers with data
  650.  
  651.     clr     r24                         // Buffer 0
  652.     rcall   WS2_WriteBuf
  653.  
  654.     sts     WS2_DMA(A, TRFCNT), r24      // set number of bytes for DMA
  655.     sts     WS2_DMA(A, TRFCNT+1), r25
  656.  
  657.     ldd     r24, Z+WSD2_EndFlag
  658.     tst     r24                         // already end?
  659.     brne    WS2_out_start                // yes!
  660.  
  661.     lds     r24, WS2_DMA(B, CTRLA)       // enable repeat for channel B
  662.     ori     r24, DMA_CH_REPEAT_bm
  663.     sts     WS2_DMA(B, CTRLA), r24
  664.  
  665.     ldi     r24, 1                      // Buffer 1
  666.     rcall   WS2_WriteBuf
  667.  
  668.     sts     WS2_DMA(B, TRFCNT), r24      // set number of byes for DMA
  669.     sts     WS2_DMA(B, TRFCNT+1), r25
  670.  
  671.     ldd     r24, Z+WSD2_EndFlag
  672.     tst     r24                         // already end?
  673.     brne    WS2_out_start                // yes!
  674.  
  675.     lds     r24, WS2_DMA(A, CTRLA)       // enable repeat for channel A
  676.     ori     r24, DMA_CH_REPEAT_bm
  677.     sts     WS2_DMA(A, CTRLA), r24
  678.  
  679.     // Enable DMA and start counter
  680.  
  681. WS2_out_start:
  682.     ldi     r24, 1
  683.     sts     WS2_TC(WS2_TCC, CNT), r24     // Init counter with 1 to avoid HIGH state on first run
  684.     sts     WS2_TC(WS2_TCC, CCA), r1
  685.  
  686.     lds     r24, WS2_DMA(A, CTRLA)       // Enable DMA channel A
  687.     ori     r24, DMA_CH_ENABLE_bm
  688.     sts     WS2_DMA(A, CTRLA), r24
  689.  
  690.     ldi     r24, (0x01<<TC0_CLKSEL_gp)  // Start timer
  691.     sts     WS2_TC(WS2_TCC, CTRLA), r24
  692.  
  693.     ldi     r24, 1<<WS2_EVSYS_CH         // STROBE EVSYS
  694.     sts     EVSYS_STROBE, r24
  695.  
  696.     clr     r24
  697.  
  698. WS2_out0:
  699.     pop     r29
  700.     pop     r28
  701.     ret
  702.  
  703.  
  704.  
  705. //****************************************************************************
  706. //  DMA_CHx_vect (private)
  707. //
  708. //  DESCR:
  709. //      Interrupt subroutines called when DMA for channel a or b finishes.
  710. //      As we are using double buffered mode, when one DMA finishes, we can
  711. //      refill the associated buffer with new data.
  712. //      When there is no more data available, the DMA for this channel will
  713. //      be disabled.
  714. //
  715. //  IN:
  716. //
  717. //  OUT:
  718. //
  719. //  SCRATCH:
  720. //      We have to save everything
  721. //
  722.  
  723.     // Funny thing to mention: Disabling repeat for a channel in dbufmode
  724.     // means that output will stop BEFORE it starts when the channel would
  725.     // have becom active
  726.  
  727.     // Channel A finished
  728.  
  729. .global WS_MERGE(DMA_, WS1_DMA_A, _vect)
  730. WS_MERGE(DMA_, WS1_DMA_A, _vect):
  731.     MPUSH   r20, r21, r22, r23, r24
  732.     in      r20, SREG
  733.     push    r20
  734.  
  735.     ldi     r20, lo8(WS_DMA(A, CTRLA))  // r20/r21 = Base DMA A
  736.     ldi     r21, hi8(WS_DMA(A, CTRLA))
  737.     ldi     r22, lo8(WS_DMA(B, CTRLA))  // r22/r23 = Base DMA B
  738.     ldi     r23, hi8(WS_DMA(B, CTRLA))
  739.     clr     r24                         // Buffer = 0
  740.     rcall   WS1_DMA_ISR
  741.  
  742.     pop     r20
  743.     out     SREG, r20
  744.     MPOP    r24, r23, r22, r21, r20
  745.     reti
  746.  
  747. .global WS_MERGE(DMA_, WS1_DMA_B, _vect)
  748. WS_MERGE(DMA_, WS1_DMA_B, _vect):
  749.     MPUSH   r20, r21, r22, r23, r24
  750.     in      r20, SREG
  751.     push    r20
  752.  
  753.     ldi     r20, lo8(WS_DMA(B, CTRLA))  // r20/r21 = Base DMA A
  754.     ldi     r21, hi8(WS_DMA(B, CTRLA))
  755.     ldi     r22, lo8(WS_DMA(A, CTRLA))  // r22/r23 = Base DMA B
  756.     ldi     r23, hi8(WS_DMA(A, CTRLA))
  757.     ldi     r24, 1                      // Buffer = 1
  758.     rcall   WS1_DMA_ISR
  759.  
  760.     pop     r20
  761.     out     SREG, r20
  762.     MPOP    r24, r23, r22, r21, r20
  763.     reti
  764.  
  765. WS1_DMA_ISR:
  766.     MPUSH   r0, r1, r18, r19, r25, r26, r27, r28, r29, r30, r31
  767.  
  768.     mov     r0, r24                     // Signal for Debugging
  769.     inc     r0
  770.     lsl     r0
  771.     sts     PORTC_OUTSET, r0
  772.  
  773.     clr     r1
  774.  
  775.     ldi     r30, lo8(WSData)            // Z = Ptr. to data struct
  776.     ldi     r31, hi8(WSData)
  777.  
  778.     ldd     r0, Z+WSD_EndFlag           // already finished?
  779.     tst     r0
  780.     brne    WS1_DMA_ISR_End              // yes!
  781.  
  782.     MPUSH   r20, r21, r22, r23
  783.     rcall   WS1_WriteBuf                 // Prepare DMA buffer
  784.     MPOP    r23, r22, r21, r20
  785.  
  786.     movw    r28, r20                    // Y = Base of own DMA
  787.     std     Y+WS_DMA_R(A, TRFCNT), r24  // set number of bytes for DMA
  788.     std     Y+WS_DMA_R(A, TRFCNT+1), r25
  789.  
  790.     ldd     r0, Z+WSD_EndFlag
  791.     tst     r0                          // end?
  792.     breq    WS1_DMA_ISR0                 // no
  793.  
  794. WS1_DMA_ISR_stop:
  795.     movw    r28, r22                    // Y = Base of other DMA
  796.     ldd     r24, Y+WS_DMA_R(B, CTRLA)   // disable repeat
  797.     andi    r24, ~DMA_CH_REPEAT_bm
  798.     std     Y+WS_DMA_R(B, CTRLA), r24    
  799.  
  800. WS1_DMA_ISR0:
  801.     movw    r28, r20                    // Y = Base of own DMA
  802.     ldd     r0, Y+WS_DMA_R(A, CTRLB)    // clear TRNIF flag
  803.     std     Y+WS_DMA_R(A, CTRLB), r0
  804.  
  805.     ldi     r24, 0x06                   // clear debug signal
  806.     sts     PORTC_OUTCLR, r24
  807.  
  808.     MPOP    r31, r30, r29, r28, r27, r26, r25, r19, r18, r1, r0
  809.     ret
  810.  
  811. WS1_DMA_ISR_End:
  812.     movw    r28, r20                    // Y = Base of own DMA
  813.     ldd     r24, Y+WS_DMA_R(A, CTRLA)   // disable DMA channel
  814.     andi    r24, ~DMA_CH_ENABLE_bm
  815.     std     Y+WS_DMA_R(A, CTRLA), r24
  816.  
  817.     movw    r28, r22                    // Y = Base of other DMA
  818.     ldd     r24, Y+WS_DMA_R(B, CTRLA)   // still active?
  819.     andi    r24, DMA_CH_REPEAT_bm
  820.     brne    WS1_DMA_ISR_stop             // yes
  821.  
  822. WS1_DMA_ISR_WaitEnd:
  823.     lds     r24, WS_TC(WS1_TCC, CCA)     // endbyte in CCA set?
  824.     cpi     r24, WS_ENDBYTE
  825.     brne    WS1_DMA_ISR_WaitEnd          // no -> wait
  826.  
  827.     sts     WS_TC(WS1_TCC, CTRLA), r1    // stop timer
  828.     sts     WS_TC(WS1_TCC, CTRLC), r1    // force output low
  829.  
  830.     rjmp    WS1_DMA_ISR0
  831.  
  832. //****************************************************************************
  833. //  DMA_CHx_vect (private)
  834. //
  835. //  DESCR:
  836. //      Interrupt subroutines called when DMA for channel a or b finishes.
  837. //      As we are using double buffered mode, when one DMA finishes, we can
  838. //      refill the associated buffer with new data.
  839. //      When there is no more data available, the DMA for this channel will
  840. //      be disabled.
  841. //
  842. //  IN:
  843. //
  844. //  OUT:
  845. //
  846. //  SCRATCH:
  847. //      We have to save everything
  848. //
  849.  
  850.     // Funny thing to mention: Disabling repeat for a channel in dbufmode
  851.     // means that output will stop BEFORE it starts when the channel would
  852.     // have becom active
  853.  
  854.     // Channel A finished
  855.  
  856. .global WS2_MERGE(DMA_, WS2_DMA_C, _vect)
  857. WS2_MERGE(DMA_, WS2_DMA_C, _vect):
  858.     MPUSH   r20, r21, r22, r23, r24
  859.     in      r20, SREG
  860.     push    r20
  861.  
  862.     ldi     r20, lo8(WS2_DMA(A, CTRLA))  // r20/r21 = Base DMA A
  863.     ldi     r21, hi8(WS2_DMA(A, CTRLA))
  864.     ldi     r22, lo8(WS2_DMA(B, CTRLA))  // r22/r23 = Base DMA B
  865.     ldi     r23, hi8(WS2_DMA(B, CTRLA))
  866.     clr     r24                         // Buffer = 0
  867.     rcall   WS2_DMA_ISR
  868.  
  869.     pop     r20
  870.     out     SREG, r20
  871.     MPOP    r24, r23, r22, r21, r20
  872.     reti
  873.  
  874. .global WS2_MERGE(DMA_, WS2_DMA_D, _vect)
  875. WS2_MERGE(DMA_, WS2_DMA_D, _vect):
  876.     MPUSH   r20, r21, r22, r23, r24
  877.     in      r20, SREG
  878.     push    r20
  879.  
  880.     ldi     r20, lo8(WS2_DMA(A, CTRLA))  // r20/r21 = Base DMA A
  881.     ldi     r21, hi8(WS2_DMA(A, CTRLA))
  882.     ldi     r22, lo8(WS2_DMA(B, CTRLA))  // r22/r23 = Base DMA B
  883.     ldi     r23, hi8(WS2_DMA(B, CTRLA))
  884.     ldi     r24, 1                      // Buffer = 1
  885.     rcall   WS2_DMA_ISR
  886.  
  887.     pop     r20
  888.     out     SREG, r20
  889.     MPOP    r24, r23, r22, r21, r20
  890.     reti
  891.  
  892. WS2_DMA_ISR:
  893.     MPUSH   r0, r1, r18, r19, r25, r26, r27, r28, r29, r30, r31
  894.  
  895.     mov     r0, r24                     // Signal for Debugging
  896.     inc     r0
  897.     lsl     r0
  898.     sts     PORTC_OUTSET, r0
  899.  
  900.     clr     r1
  901.  
  902.     ldi     r30, lo8(WS2Data)            // Z = Ptr. to data struct
  903.     ldi     r31, hi8(WS2Data)
  904.  
  905.     ldd     r0, Z+WSD2_EndFlag           // already finished?
  906.     tst     r0
  907.     brne    WS2_DMA_ISR_End              // yes!
  908.  
  909.     MPUSH   r20, r21, r22, r23
  910.     rcall   WS2_WriteBuf                 // Prepare DMA buffer
  911.     MPOP    r23, r22, r21, r20
  912.  
  913.     movw    r28, r20                    // Y = Base of own DMA
  914.     std     Y+WS2_DMA_R(A, TRFCNT), r24  // set number of bytes for DMA
  915.     std     Y+WS2_DMA_R(A, TRFCNT+1), r25
  916.  
  917.     ldd     r0, Z+WSD2_EndFlag
  918.     tst     r0                          // end?
  919.     breq    WS2_DMA_ISR0                 // no
  920.  
  921. WS2_DMA_ISR_stop:
  922.     movw    r28, r22                    // Y = Base of other DMA
  923.     ldd     r24, Y+WS2_DMA_R(B, CTRLA)   // disable repeat
  924.     andi    r24, ~DMA_CH_REPEAT_bm
  925.     std     Y+WS2_DMA_R(B, CTRLA), r24    
  926.  
  927. WS2_DMA_ISR0:
  928.     movw    r28, r20                    // Y = Base of own DMA
  929.     ldd     r0, Y+WS2_DMA_R(A, CTRLB)    // clear TRNIF flag
  930.     std     Y+WS2_DMA_R(A, CTRLB), r0
  931.  
  932.     ldi     r24, 0x06                   // clear debug signal
  933.     sts     PORTC_OUTCLR, r24
  934.  
  935.     MPOP    r31, r30, r29, r28, r27, r26, r25, r19, r18, r1, r0
  936.     ret
  937.  
  938. WS2_DMA_ISR_End:
  939.     movw    r28, r20                    // Y = Base of own DMA
  940.     ldd     r24, Y+WS2_DMA_R(C, CTRLA)   // disable DMA channel
  941.     andi    r24, ~DMA_CH_ENABLE_bm
  942.     std     Y+WS2_DMA_R(C, CTRLA), r24
  943.  
  944.     movw    r28, r22                    // Y = Base of other DMA
  945.     ldd     r24, Y+WS2_DMA_R(D, CTRLA)   // still active?
  946.     andi    r24, DMA_CH_REPEAT_bm
  947.     brne    WS2_DMA_ISR_stop             // yes
  948.  
  949. WS2_DMA_ISR_WaitEnd:
  950.     lds     r24, WS2_TC(WS2_TCC, CCA)     // endbyte in CCA set?
  951.     cpi     r24, WS2_ENDBYTE
  952.     brne    WS2_DMA_ISR_WaitEnd          // no -> wait
  953.  
  954.     sts     WS2_TC(WS2_TCC, CTRLA), r1    // stop timer
  955.     sts     WS2_TC(WS2_TCC, CTRLC), r1    // force output low
  956.  
  957.     rjmp    WS2_DMA_ISR0
  958.  
  959.  
  960. //****************************************************************************
  961. //  WS_WriteBuf (private)
  962. //
  963. //  DESCR:
  964. //      Read bytes from input ptr, convert them into pwm values and write
  965. //      them into the next available dma buffer.
  966. //      When end of input data is reached, write 0xff as end byte.
  967. //
  968. //  IN:
  969. //      r30/r31 (Z) : Ptr. to WSD
  970. //      r24         : BUffer to write 0/1
  971. //
  972. //  OUT:
  973. //      r24/r25 : Num bytes written
  974. //
  975. //  SCRATCH:
  976. //      r0, r18, r19, r20, r21, r22/r23, r24/r25, r26/r27, r28/r29
  977. //
  978. WS1_WriteBuf:
  979.     clr     r1
  980.  
  981.     movw    r26, r30                    // WSD -> X
  982.     lsl     r24                         // Buffer number *2
  983.     ldi     r25, WSD_BufAPtr
  984.     add     r24, r25
  985.     add     r26, r24                    // Get adr. of WSD_BufxPtr
  986.     adc     r27, r1
  987.  
  988.     ld      r28, X+                     // Get ptr. in Y
  989.     ld      r29, X+
  990.  
  991.     ldd     r22, Z+WSD_OutCnt           // r22/r23,r24/r25 = Number of bytes left
  992.     ldd     r23, Z+WSD_OutCnt+1
  993.     movw    r24, r22
  994.     adiw    r24, 0                      // zero bytes left?
  995.     breq    WS1_WriteBuf_OutEnd          // yes!
  996.  
  997.     ldi     r18, (WS_BUFNUM/2)&0xff
  998.     ldi     r19, (WS_BUFNUM/2)>>8
  999.     cp      r18, r24                    // bytes to output > numbuf/2?
  1000.     cpc     r19, r25
  1001.     brsh    WS1_WriteBuf1
  1002.  
  1003.     mov     r24, r18                    // yes, bytes to output = numbuf/2
  1004.     mov     r25, r19
  1005.  
  1006. WS1_WriteBuf1:
  1007.     sub     r22, r24                    // Num of bytes left -= bytes to output
  1008.     sbc     r23, r25
  1009.     std     Z+WSD_OutCnt, r22           // store
  1010.     std     Z+WSD_OutCnt+1, r23
  1011.  
  1012.     ldd     r26, Z+WSD_OutPtr           // r26/r27 (X) = ptr to output data
  1013.     ldd     r27, Z+WSD_OutPtr+1
  1014.  
  1015.     ldd     r22, Z+WSD_GammaPtr         // r22/r23 = Ptr. to gamma table
  1016.     ldd     r23, Z+WSD_GammaPtr+1
  1017.  
  1018.     push    r28
  1019.     push    r29
  1020.     push    r30
  1021.     push    r31
  1022.  
  1023.     rcall   WS1_Byte2PWM
  1024.  
  1025.     pop     r31
  1026.     pop     r30
  1027.  
  1028.     std     Z+WSD_OutPtr, r26           // store new OutPtr
  1029.     std     Z+WSD_OutPtr+1, r27
  1030.  
  1031.     pop     r27
  1032.     pop     r26
  1033.  
  1034.     movw    r24, r28                    // calc. number bytes written in r24
  1035.     sub     r24, r26
  1036.     sbc     r25, r27  
  1037.  
  1038.     // Check if we have used whole buffer
  1039.  
  1040.     cpi     r24, (WS_BUFSIZE/2)&0xff
  1041.     brne    WS1_WriteBuf_OutEnd
  1042.     cpi     r25, (WS_BUFSIZE/2)>>8
  1043.     breq    WS1_WriteBuf0
  1044.  
  1045.     // We have no end of buffer reached, that means: We are finished with data
  1046.     // and also there is some place left in buffer to store the "end byte" 0xff
  1047.  
  1048. WS1_WriteBuf_OutEnd:
  1049.     ldi     r22, WS_ENDBYTE             // write "end byte"
  1050.     st      Y, r22
  1051.     ldi     r22, 1                      // Set Endflag
  1052.     std     Z+WSD_EndFlag, r22
  1053.     adiw    r24, 1
  1054.  
  1055. WS1_WriteBuf0:
  1056.     ret
  1057.  
  1058. //****************************************************************************
  1059. //  WS2_WriteBuf (private)
  1060. //
  1061. //  DESCR:
  1062. //      Read bytes from input ptr, convert them into pwm values and write
  1063. //      them into the next available dma buffer.
  1064. //      When end of input data is reached, write 0xff as end byte.
  1065. //
  1066. //  IN:
  1067. //      r30/r31 (Z) : Ptr. to WSD
  1068. //      r24         : BUffer to write 0/1
  1069. //
  1070. //  OUT:
  1071. //      r24/r25 : Num bytes written
  1072. //
  1073. //  SCRATCH:
  1074. //      r0, r18, r19, r20, r21, r22/r23, r24/r25, r26/r27, r28/r29
  1075. //
  1076. WS2_WriteBuf:
  1077.     clr     r1
  1078.  
  1079.     movw    r26, r30                    // WSD -> X
  1080.     lsl     r24                         // Buffer number *2
  1081.     ldi     r25, WSD2_BufAPtr
  1082.     add     r24, r25
  1083.     add     r26, r24                    // Get adr. of WSD_BufxPtr
  1084.     adc     r27, r1
  1085.  
  1086.     ld      r28, X+                     // Get ptr. in Y
  1087.     ld      r29, X+
  1088.  
  1089.     ldd     r22, Z+WSD2_OutCnt           // r22/r23,r24/r25 = Number of bytes left
  1090.     ldd     r23, Z+WSD2_OutCnt+1
  1091.     movw    r24, r22
  1092.     adiw    r24, 0                      // zero bytes left?
  1093.     breq    WS2_WriteBuf_OutEnd          // yes!
  1094.  
  1095.     ldi     r18, (WS_BUFNUM/2)&0xff
  1096.     ldi     r19, (WS_BUFNUM/2)>>8
  1097.     cp      r18, r24                    // bytes to output > numbuf/2?
  1098.     cpc     r19, r25
  1099.     brsh    WS2_WriteBuf1
  1100.  
  1101.     mov     r24, r18                    // yes, bytes to output = numbuf/2
  1102.     mov     r25, r19
  1103.  
  1104. WS2_WriteBuf1:
  1105.     sub     r22, r24                    // Num of bytes left -= bytes to output
  1106.     sbc     r23, r25
  1107.     std     Z+WSD2_OutCnt, r22           // store
  1108.     std     Z+WSD2_OutCnt+1, r23
  1109.  
  1110.     ldd     r26, Z+WSD2_OutPtr           // r26/r27 (X) = ptr to output data
  1111.     ldd     r27, Z+WSD2_OutPtr+1
  1112.  
  1113.     ldd     r22, Z+WSD2_GammaPtr         // r22/r23 = Ptr. to gamma table
  1114.     ldd     r23, Z+WSD2_GammaPtr+1
  1115.  
  1116.     push    r28
  1117.     push    r29
  1118.     push    r30
  1119.     push    r31
  1120.  
  1121.     rcall   WS2_Byte2PWM
  1122.  
  1123.     pop     r31
  1124.     pop     r30
  1125.  
  1126.     std     Z+WSD2_OutPtr, r26           // store new OutPtr
  1127.     std     Z+WSD2_OutPtr+1, r27
  1128.  
  1129.     pop     r27
  1130.     pop     r26
  1131.  
  1132.     movw    r24, r28                    // calc. number bytes written in r24
  1133.     sub     r24, r26
  1134.     sbc     r25, r27  
  1135.  
  1136.     // Check if we have used whole buffer
  1137.  
  1138.     cpi     r24, (WS_BUFSIZE/2)&0xff
  1139.     brne    WS2_WriteBuf_OutEnd
  1140.     cpi     r25, (WS_BUFSIZE/2)>>8
  1141.     breq    WS2_WriteBuf0
  1142.  
  1143.     // We have no end of buffer reached, that means: We are finished with data
  1144.     // and also there is some place left in buffer to store the "end byte" 0xff
  1145.  
  1146. WS2_WriteBuf_OutEnd:
  1147.     ldi     r22, WS_ENDBYTE             // write "end byte"
  1148.     st      Y, r22
  1149.     ldi     r22, 1                      // Set Endflag
  1150.     std     Z+WSD2_EndFlag, r22
  1151.     adiw    r24, 1
  1152.  
  1153. WS2_WriteBuf0:
  1154.     ret
  1155.  
  1156.  
  1157.  
  1158. //****************************************************************************
  1159. //  WS_Byte2PWM (private)
  1160. //
  1161. //  DESCR:
  1162. //      Convert input bytes to stream of PWM values
  1163. //
  1164. //  IN:
  1165. //      r22/r23     : Ptr. to Gammatable
  1166. //      r24/r25     : Number of bytes
  1167. //      r26/r27 (X) : Ptr. to bytes
  1168. //      r28/r29 (Y) : Ptr. to dest. buffer
  1169. //
  1170. //  OUT:
  1171. //      r26/r27 (X) : New ptr. to bytes
  1172. //      r28/r29 (Y) : New ptr. to dest. buffer behind
  1173. //
  1174. //  SCRATCH:
  1175. //      r0, r18, r19, r20, r21, r24/r25, r30/r31
  1176. //
  1177. WS1_Byte2PWM:
  1178.     ldi     r19, WS_CNT_LOW             // r19 = value for low
  1179.     ldi     r20, WS_CNT_HIGH            // r20 = value for high
  1180.     mov     r21, r22
  1181.     or      r21, r23                    // r21 = flag for Gammatable
  1182.  
  1183. WS1_Byte2PWM_loop2:
  1184.     sbiw    r24, 1
  1185.     brlt    WS1_Byte2PWM0
  1186.  
  1187.     ld      r0, X+                      // Get next byte
  1188. //    tst     r21                         // Gammatable?
  1189. //    breq    WS1_Byte2PWM_nogamma
  1190.  
  1191. //    movw    r30, r22                    // start of gammatable into r30
  1192. //    add     r30, r0                     // add byte val.
  1193. //    adc     r31, r1
  1194. //    lpm     r0, Z                       // get new value from table
  1195.  
  1196. WS1_Byte2PWM_nogamma:
  1197.     ldi     r18, 8                      // r18 = Bitcounter
  1198.  
  1199. WS1_Byte2PWM_loop:
  1200.     lsl     r0
  1201.     brcs    WS1_Byte2PWM_high
  1202.     st      Y+, r19
  1203.     dec     r18
  1204.     brne    WS1_Byte2PWM_loop
  1205.     rjmp    WS1_Byte2PWM_loop2
  1206.  
  1207. WS1_Byte2PWM_high:
  1208.     st      Y+, r20
  1209.     dec     r18
  1210.     brne    WS1_Byte2PWM_loop
  1211.     rjmp    WS1_Byte2PWM_loop2
  1212.  
  1213. WS1_Byte2PWM0:
  1214.     ret
  1215.  
  1216. //****************************************************************************
  1217. //  WS2_Byte2PWM (private)
  1218. //
  1219. //  DESCR:
  1220. //      Convert input bytes to stream of PWM values
  1221. //
  1222. //  IN:
  1223. //      r22/r23     : Ptr. to Gammatable
  1224. //      r24/r25     : Number of bytes
  1225. //      r26/r27 (X) : Ptr. to bytes
  1226. //      r28/r29 (Y) : Ptr. to dest. buffer
  1227. //
  1228. //  OUT:
  1229. //      r26/r27 (X) : New ptr. to bytes
  1230. //      r28/r29 (Y) : New ptr. to dest. buffer behind
  1231. //
  1232. //  SCRATCH:
  1233. //      r0, r18, r19, r20, r21, r24/r25, r30/r31
  1234. //
  1235. WS2_Byte2PWM:
  1236.     ldi     r19, WS_CNT_LOW             // r19 = value for low
  1237.     ldi     r20, WS_CNT_HIGH            // r20 = value for high
  1238.     mov     r21, r22
  1239.     or      r21, r23                    // r21 = flag for Gammatable
  1240.  
  1241. WS2_Byte2PWM_loop2:
  1242.     sbiw    r24, 1
  1243.     brlt    WS2_Byte2PWM0
  1244.  
  1245.     ld      r0, X+                      // Get next byte
  1246. //    tst     r21                         // Gammatable?
  1247. //    breq    WS2_Byte2PWM_nogamma
  1248.  
  1249. //    movw    r30, r22                    // start of gammatable into r30
  1250. //    add     r30, r0                     // add byte val.
  1251. //    adc     r31, r1
  1252. //    lpm     r0, Z                       // get new value from table
  1253.  
  1254. WS2_Byte2PWM_nogamma:
  1255.     ldi     r18, 8                      // r18 = Bitcounter
  1256.  
  1257. WS2_Byte2PWM_loop:
  1258.     lsl     r0
  1259.     brcs    WS2_Byte2PWM_high
  1260.     st      Y+, r19
  1261.     dec     r18
  1262.     brne    WS2_Byte2PWM_loop
  1263.     rjmp    WS2_Byte2PWM_loop2
  1264.  
  1265. WS2_Byte2PWM_high:
  1266.     st      Y+, r20
  1267.     dec     r18
  1268.     brne    WS2_Byte2PWM_loop
  1269.     rjmp    WS2_Byte2PWM_loop2
  1270.  
  1271. WS2_Byte2PWM0:
  1272.     ret
  1273.  
  1274.  
  1275.  
  1276. //****************************************************************************
  1277. //      uint8_t WS_outCheck(void)
  1278. //
  1279. //  DESCR
  1280. //      Check if output of last data is finished.
  1281. //
  1282. //  OUT:
  1283. //      r24: uint8_t status      0=OK, 1=DMA busy
  1284. //
  1285. .global WS1_outCheck
  1286.     lds     r24, DMA_STATUS             // check if DMA is still in progress
  1287.     andi    r24, WS1_DMA_BUSY_bm
  1288.     breq    WS1_outCheck0                // zero -> no active DMA
  1289.  
  1290.     ldi     r24, 1                      // ret = 1 (busy)
  1291.  
  1292. WS1_outCheck0:
  1293.     ret
  1294.  
  1295. //****************************************************************************
  1296. //      uint8_t WS_outCheck(void)
  1297. //
  1298. //  DESCR
  1299. //      Check if output of last data is finished.
  1300. //
  1301. //  OUT:
  1302. //      r24: uint8_t status      0=OK, 1=DMA busy
  1303. //
  1304. .global WS2_outCheck
  1305.     lds     r24, DMA_STATUS             // check if DMA is still in progress
  1306.     andi    r24, WS2_DMA_BUSY_bm
  1307.     breq    WS2_outCheck0                // zero -> no active DMA
  1308.  
  1309.      ldi     r24, 1                      // ret = 1 (busy)
  1310.  
  1311. WS2_outCheck0:
  1312.     ret
  1313.  
  1314.  
  1315.  
  1316. //****************************************************************************
  1317. //  DATA
  1318. //
  1319. .section .bss
  1320. WSData:
  1321.     .space  WSD_SizeOf
  1322. WS_BufferA:
  1323.     .space  WS_BUFSIZE/2
  1324. WS_BufferA_End:
  1325. WS_BufferB:
  1326.     .space  WS_BUFSIZE/2
  1327. WS_BufferB_End:
  1328. WS2Data:
  1329.     .space  WSD_SizeOf
  1330. WS2_BufferA:
  1331.     .space  WS_BUFSIZE/2
  1332. WS2_BufferA_End:
  1333. WS2_BufferB:
  1334.     .space  WS_BUFSIZE/2
  1335. WS2_BufferB_End:
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement