Guest User

Untitled

a guest
Jan 13th, 2018
70
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 16.15 KB | None | 0 0
  1. // This simplified demo scrolls the text of the Jaberwoky poem directly from flash memory
  2. // Full article at http://wp.josh.com/2016/05/20/huge-scrolling-arduino-led-sign/
  3.  
  4. // Change this to be at least as long as your pixel string (too long will work fine, just be a little slower)
  5.  
  6. #define PIXELS 96*4 // Number of pixels in the string. I am using 4 meters of 96LED/M
  7.  
  8. // These values depend on which pins your 8 strings are connected to and what board you are using
  9. // More info on how to find these at http://www.arduino.cc/en/Reference/PortManipulation
  10.  
  11. // PORTD controls Digital Pins 0-7 on the Uno
  12.  
  13. // You'll need to look up the port/bit combination for other boards.
  14.  
  15. // Note that you could also include the DigitalWriteFast header file to not need to to this lookup.
  16.  
  17. #define PIXEL_PORT PORTD // Port of the pin the pixels are connected to
  18. #define PIXEL_DDR DDRD // Port of the pin the pixels are connected to
  19.  
  20.  
  21. static const uint8_t onBits=0b11111110; // Bit pattern to write to port to turn on all pins connected to LED strips.
  22. // If you do not want to use all 8 pins, you can mask off the ones you don't want
  23. // Note that these will still get 0 written to them when we send pixels
  24. // TODO: If we have time, we could even add a variable that will and/or into the bits before writing to the port to support any combination of bits/values
  25.  
  26. // These are the timing constraints taken mostly from
  27. // imperically measuring the output from the Adafruit library strandtest program
  28.  
  29. // Note that some of these defined values are for refernce only - the actual timing is determinted by the hard code.
  30.  
  31. #define T1H 814 // Width of a 1 bit in ns - 13 cycles
  32. #define T1L 438 // Width of a 1 bit in ns - 7 cycles
  33.  
  34. #define T0H 312 // Width of a 0 bit in ns - 5 cycles
  35. #define T0L 936 // Width of a 0 bit in ns - 15 cycles
  36.  
  37. // Phase #1 - Always 1 - 5 cycles
  38. // Phase #2 - Data part - 8 cycles
  39. // Phase #3 - Always 0 - 7 cycles
  40.  
  41.  
  42. #define RES 50000 // Width of the low gap between bits to cause a frame to latch
  43.  
  44. // Here are some convience defines for using nanoseconds specs to generate actual CPU delays
  45.  
  46. #define NS_PER_SEC (1000000000L) // Note that this has to be SIGNED since we want to be able to check for negative values of derivatives
  47.  
  48. #define CYCLES_PER_SEC (F_CPU)
  49.  
  50. #define NS_PER_CYCLE ( NS_PER_SEC / CYCLES_PER_SEC )
  51.  
  52. #define NS_TO_CYCLES(n) ( (n) / NS_PER_CYCLE )
  53.  
  54.  
  55. // Sends a full 8 bits down all the pins, represening a single color of 1 pixel
  56. // We walk though the 8 bits in colorbyte one at a time. If the bit is 1 then we send the 8 bits of row out. Otherwise we send 0.
  57. // We send onBits at the first phase of the signal generation. We could just send 0xff, but that mught enable pull-ups on pins that we are not using.
  58.  
  59. /// Unforntunately we have to drop to ASM for this so we can interleave the computaions durring the delays, otherwise things get too slow.
  60.  
  61. // OnBits is the mask of which bits are connected to strips. We pass it on so that we
  62. // do not turn on unused pins becuase this would enable the pullup. Also, hopefully passing this
  63. // will cause the compiler to allocate a Register for it and avoid a reload every pass.
  64.  
  65. static inline void sendBitx8( const uint8_t row , const uint8_t colorbyte , const uint8_t onBits ) {
  66.  
  67. asm volatile (
  68.  
  69.  
  70. "L_%=: \n\r"
  71.  
  72. "out %[port], %[onBits] \n\t" // (1 cycles) - send either T0H or the first part of T1H. Onbits is a mask of which bits have strings attached.
  73.  
  74. // Next determine if we are going to be sending 1s or 0s based on the current bit in the color....
  75.  
  76. "mov r0, %[bitwalker] \n\t" // (1 cycles)
  77. "and r0, %[colorbyte] \n\t" // (1 cycles) - is the current bit in the color byte set?
  78. "breq OFF_%= \n\t" // (1 cycles) - bit in color is 0, then send full zero row (takes 2 cycles if branch taken, count the extra 1 on the target line)
  79.  
  80. // If we get here, then we want to send a 1 for every row that has an ON dot...
  81. "nop \n\t " // (1 cycles)
  82. "out %[port], %[row] \n\t" // (1 cycles) - set the output bits to [row] This is phase for T0H-T1H.
  83. // ==========
  84. // (5 cycles) - T0H (Phase #1)
  85.  
  86.  
  87. "nop \n\t nop \n\t " // (2 cycles)
  88. "nop \n\t nop \n\t " // (2 cycles)
  89. "nop \n\t nop \n\t " // (2 cycles)
  90. "nop \n\t " // (1 cycles)
  91.  
  92. "out %[port], __zero_reg__ \n\t" // (1 cycles) - set the output bits to 0x00 based on the bit in colorbyte. This is phase for T0H-T1H
  93. // ==========
  94. // (8 cycles) - Phase #2
  95.  
  96. "ror %[bitwalker] \n\t" // (1 cycles) - get ready for next pass. On last pass, the bit will end up in C flag
  97.  
  98. "brcs DONE_%= \n\t" // (1 cycles) Exit if carry bit is set as a result of us walking all 8 bits. We assume that the process around us will tak long enough to cover the phase 3 delay
  99.  
  100. "nop \n\t \n\t " // (1 cycles) - When added to the 5 cycles in S:, we gte the 7 cycles of T1L
  101.  
  102. "jmp L_%= \n\t" // (3 cycles)
  103. // (1 cycles) - The OUT on the next pass of the loop
  104. // ==========
  105. // (7 cycles) - T1L
  106.  
  107.  
  108. "OFF_%=: \n\r" // (1 cycles) Note that we land here becuase of breq, which takes takes 2 cycles
  109.  
  110. "out %[port], __zero_reg__ \n\t" // (1 cycles) - set the output bits to 0x00 based on the bit in colorbyte. This is phase for T0H-T1H
  111. // ==========
  112. // (5 cycles) - T0H
  113.  
  114. "ror %[bitwalker] \n\t" // (1 cycles) - get ready for next pass. On last pass, the bit will end up in C flag
  115.  
  116. "brcs DONE_%= \n\t" // (1 cycles) Exit if carry bit is set as a result of us walking all 8 bits. We assume that the process around us will tak long enough to cover the phase 3 delay
  117.  
  118. "nop \n\t nop \n\t " // (2 cycles)
  119. "nop \n\t nop \n\t " // (2 cycles)
  120. "nop \n\t nop \n\t " // (2 cycles)
  121. "nop \n\t nop \n\t " // (2 cycles)
  122. "nop \n\t " // (1 cycles)
  123.  
  124. "jmp L_%= \n\t" // (3 cycles)
  125. // (1 cycles) - The OUT on the next pass of the loop
  126. // ==========
  127. //(15 cycles) - T0L
  128.  
  129.  
  130. "DONE_%=: \n\t"
  131.  
  132. // Don't need an explicit delay here since the overhead that follows will always be long enough
  133.  
  134. ::
  135. [port] "I" (_SFR_IO_ADDR(PIXEL_PORT)),
  136. [row] "d" (row),
  137. [onBits] "d" (onBits),
  138. [colorbyte] "d" (colorbyte ), // Phase 2 of the signal where the actual data bits show up.
  139. [bitwalker] "r" (0x80) // Alocate a register to hold a bit that we will walk down though the color byte
  140.  
  141. );
  142.  
  143. // Note that the inter-bit gap can be as long as you want as long as it doesn't exceed the reset timeout (which is A long time)
  144.  
  145. }
  146.  
  147.  
  148.  
  149.  
  150. // Just wait long enough without sending any bots to cause the pixels to latch and display the last sent frame
  151.  
  152. void show() {
  153. delayMicroseconds( (RES / 1000UL) + 1); // Round up since the delay must be _at_least_ this long (too short might not work, too long not a problem)
  154. }
  155.  
  156.  
  157. // Send 3 bytes of color data (R,G,B) for a signle pixel down all the connected stringsat the same time
  158. // A 1 bit in "row" means send the color, a 0 bit means send black.
  159.  
  160. static inline void sendRowRGB( uint8_t row , uint8_t r, uint8_t g, uint8_t b ) {
  161.  
  162. sendBitx8( row , g , onBits); // WS2812 takes colors in GRB order
  163. sendBitx8( row , r , onBits); // WS2812 takes colors in GRB order
  164. sendBitx8( row , b , onBits); // WS2812 takes colors in GRB order
  165.  
  166. }
  167.  
  168. // This nice 5x7 font from here...
  169. // http://sunge.awardspace.com/glcd-sd/node4.html
  170.  
  171. // Font details:
  172. // 1) Each char is fixed 5x7 pixels.
  173. // 2) Each byte is one column.
  174. // 3) Columns are left to right order, leftmost byte is leftmost column of pixels.
  175. // 4) Each column is 8 bits high.
  176. // 5) Bit #7 is top line of char, Bit #1 is bottom.
  177. // 6) Bit #0 is always 0, becuase this pin is used as serial input and setting to 1 would enable the pull-up.
  178.  
  179. // defines ascii characters 0x20-0x7F (32-127)
  180. // PROGMEM after variable name as per https://www.arduino.cc/en/Reference/PROGMEM
  181.  
  182. #define FONT_WIDTH 5
  183. #define INTERCHAR_SPACE 1
  184. #define ASCII_OFFSET 0x20 // ASSCI code of 1st char in font array
  185.  
  186. const uint8_t Font5x7[] PROGMEM = {
  187. 0x00,0x00,0x00,0x00,0x00,//
  188. 0x00,0x00,0xfa,0x00,0x00,// !
  189. 0x00,0xe0,0x00,0xe0,0x00,// "
  190. 0x28,0xfe,0x28,0xfe,0x28,// #
  191. 0x24,0x54,0xfe,0x54,0x48,// $
  192. 0xc4,0xc8,0x10,0x26,0x46,// %
  193. 0x6c,0x92,0xaa,0x44,0x0a,// &
  194. 0x00,0xa0,0xc0,0x00,0x00,// '
  195. 0x00,0x38,0x44,0x82,0x00,// (
  196. 0x00,0x82,0x44,0x38,0x00,// )
  197. 0x10,0x54,0x38,0x54,0x10,// *
  198. 0x10,0x10,0x7c,0x10,0x10,// +
  199. 0x00,0x0a,0x0c,0x00,0x00,// ,
  200. 0x10,0x10,0x10,0x10,0x10,// -
  201. 0x00,0x06,0x06,0x00,0x00,// .
  202. 0x04,0x08,0x10,0x20,0x40,// /
  203. 0x7c,0x8a,0x92,0xa2,0x7c,// 0
  204. 0x00,0x42,0xfe,0x02,0x00,// 1
  205. 0x42,0x86,0x8a,0x92,0x62,// 2
  206. 0x84,0x82,0xa2,0xd2,0x8c,// 3
  207. 0x18,0x28,0x48,0xfe,0x08,// 4
  208. 0xe4,0xa2,0xa2,0xa2,0x9c,// 5
  209. 0x3c,0x52,0x92,0x92,0x0c,// 6
  210. 0x80,0x8e,0x90,0xa0,0xc0,// 7
  211. 0x6c,0x92,0x92,0x92,0x6c,// 8
  212. 0x60,0x92,0x92,0x94,0x78,// 9
  213. 0x00,0x6c,0x6c,0x00,0x00,// :
  214. 0x00,0x6a,0x6c,0x00,0x00,// ;
  215. 0x00,0x10,0x28,0x44,0x82,// <
  216. 0x28,0x28,0x28,0x28,0x28,// =
  217. 0x82,0x44,0x28,0x10,0x00,// >
  218. 0x40,0x80,0x8a,0x90,0x60,// ?
  219. 0x4c,0x92,0x9e,0x82,0x7c,// @
  220. 0x7e,0x88,0x88,0x88,0x7e,// A
  221. 0xfe,0x92,0x92,0x92,0x6c,// B
  222. 0x7c,0x82,0x82,0x82,0x44,// C
  223. 0xfe,0x82,0x82,0x44,0x38,// D
  224. 0xfe,0x92,0x92,0x92,0x82,// E
  225. 0xfe,0x90,0x90,0x80,0x80,// F
  226. 0x7c,0x82,0x82,0x8a,0x4c,// G
  227. 0xfe,0x10,0x10,0x10,0xfe,// H
  228. 0x00,0x82,0xfe,0x82,0x00,// I
  229. 0x04,0x02,0x82,0xfc,0x80,// J
  230. 0xfe,0x10,0x28,0x44,0x82,// K
  231. 0xfe,0x02,0x02,0x02,0x02,// L
  232. 0xfe,0x40,0x20,0x40,0xfe,// M
  233. 0xfe,0x20,0x10,0x08,0xfe,// N
  234. 0x7c,0x82,0x82,0x82,0x7c,// O
  235. 0xfe,0x90,0x90,0x90,0x60,// P
  236. 0x7c,0x82,0x8a,0x84,0x7a,// Q
  237. 0xfe,0x90,0x98,0x94,0x62,// R
  238. 0x62,0x92,0x92,0x92,0x8c,// S
  239. 0x80,0x80,0xfe,0x80,0x80,// T
  240. 0xfc,0x02,0x02,0x02,0xfc,// U
  241. 0xf8,0x04,0x02,0x04,0xf8,// V
  242. 0xfe,0x04,0x18,0x04,0xfe,// W
  243. 0xc6,0x28,0x10,0x28,0xc6,// X
  244. 0xc0,0x20,0x1e,0x20,0xc0,// Y
  245. 0x86,0x8a,0x92,0xa2,0xc2,// Z
  246. 0x00,0x00,0xfe,0x82,0x82,// [
  247. 0x40,0x20,0x10,0x08,0x04,// (backslash)
  248. 0x82,0x82,0xfe,0x00,0x00,// ]
  249. 0x20,0x40,0x80,0x40,0x20,// ^
  250. 0x02,0x02,0x02,0x02,0x02,// _
  251. 0x00,0x80,0x40,0x20,0x00,// `
  252. 0x04,0x2a,0x2a,0x2a,0x1e,// a
  253. 0xfe,0x12,0x22,0x22,0x1c,// b
  254. 0x1c,0x22,0x22,0x22,0x04,// c
  255. 0x1c,0x22,0x22,0x12,0xfe,// d
  256. 0x1c,0x2a,0x2a,0x2a,0x18,// e
  257. 0x10,0x7e,0x90,0x80,0x40,// f
  258. 0x10,0x28,0x2a,0x2a,0x3c,// g
  259. 0xfe,0x10,0x20,0x20,0x1e,// h
  260. 0x00,0x22,0xbe,0x02,0x00,// i
  261. 0x04,0x02,0x22,0xbc,0x00,// j
  262. 0x00,0xfe,0x08,0x14,0x22,// k
  263. 0x00,0x82,0xfe,0x02,0x00,// l
  264. 0x3e,0x20,0x18,0x20,0x1e,// m
  265. 0x3e,0x10,0x20,0x20,0x1e,// n
  266. 0x1c,0x22,0x22,0x22,0x1c,// o
  267. 0x3e,0x28,0x28,0x28,0x10,// p
  268. 0x10,0x28,0x28,0x18,0x3e,// q
  269. 0x3e,0x10,0x20,0x20,0x10,// r
  270. 0x12,0x2a,0x2a,0x2a,0x04,// s
  271. 0x20,0xfc,0x22,0x02,0x04,// t
  272. 0x3c,0x02,0x02,0x04,0x3e,// u
  273. 0x38,0x04,0x02,0x04,0x38,// v
  274. 0x3c,0x02,0x0c,0x02,0x3c,// w
  275. 0x22,0x14,0x08,0x14,0x22,// x
  276. 0x30,0x0a,0x0a,0x0a,0x3c,// y
  277. 0x22,0x26,0x2a,0x32,0x22,// z
  278. 0x00,0x10,0x6c,0x82,0x00,// {
  279. 0x00,0x00,0xfe,0x00,0x00,// |
  280. 0x00,0x82,0x6c,0x10,0x00,// }
  281. 0x10,0x10,0x54,0x38,0x10,// ~
  282. 0x10,0x38,0x54,0x10,0x10,// 
  283. };
  284.  
  285. // Send the pixels to form the specified char, not including interchar space
  286. // skip is the number of pixels to skip at the begining to enable sub-char smooth scrolling
  287.  
  288. // TODO: Subtract the offset from the char before starting the send sequence to save time if nessisary
  289. // TODO: Also could pad the begining of the font table to aovid the offset subtraction at the cost of 20*8 bytes of progmem
  290. // TODO: Could pad all chars out to 8 bytes wide to turn the the multiply by FONT_WIDTH into a shift
  291.  
  292. static inline void sendChar( uint8_t c , uint8_t skip , uint8_t r, uint8_t g, uint8_t b ) {
  293.  
  294. const uint8_t *charbase = Font5x7 + (( c -' ')* FONT_WIDTH ) ;
  295.  
  296. uint8_t col=FONT_WIDTH;
  297.  
  298. while (skip--) {
  299. charbase++;
  300. col--;
  301. }
  302.  
  303. while (col--) {
  304. sendRowRGB( pgm_read_byte_near( charbase++ ) , r , g , b );
  305. }
  306.  
  307. col=INTERCHAR_SPACE;
  308.  
  309. while (col--) {
  310.  
  311. sendRowRGB( 0 , r , g , b ); // Interchar space
  312.  
  313. }
  314.  
  315. }
  316.  
  317.  
  318. // Show the passed string. The last letter of the string will be in the rightmost pixels of the display.
  319. // Skip is how many cols of the 1st char to skip for smooth scrolling
  320.  
  321.  
  322. static inline void sendString( const char *s , uint8_t skip , const uint8_t r, const uint8_t g, const uint8_t b ) {
  323.  
  324. unsigned int l=PIXELS/(FONT_WIDTH+INTERCHAR_SPACE);
  325.  
  326. sendChar( *s , skip , r , g , b ); // First char is special case becuase it can be stepped for smooth scrolling
  327.  
  328. while ( *(++s) && l--) {
  329.  
  330. sendChar( *s , 0, r , g , b );
  331.  
  332. }
  333.  
  334. show();
  335. }
  336.  
  337. void setup() {
  338. PIXEL_DDR |= onBits; // Set used pins to output mode
  339. }
  340.  
  341. static char jabberText[] =
  342. " "
  343. "Twas brillig, and the slithy toves "
  344. "Did gyre and gimble in the wabe: "
  345. "All mimsy were the borogoves, "
  346. "And the mome raths outgrabe. "
  347.  
  348. "Beware the Jabberwock, my son! "
  349. "The jaws that bite, the claws that catch! "
  350. "Beware the Jubjub bird, and shun "
  351. "The frumious Bandersnatch! "
  352.  
  353. "He took his vorpal sword in hand; "
  354. "Long time the manxome foe he sought- "
  355. "So rested he by the Tumtum tree "
  356. "And stood awhile in thought. "
  357.  
  358. "And, as in uffish thought he stood, "
  359. "The Jabberwock, with eyes of flame, "
  360. "Came whiffling through the tulgey wood, "
  361. "And burbled as it came! "
  362.  
  363. "One, two! One, two! And through and through "
  364. "The vorpal blade went snicker-snack! "
  365. "He left it dead, and with its head "
  366. "He went galumphing back. "
  367.  
  368. "And hast thou slain the Jabberwock? "
  369. "Come to my arms, my beamish boy! "
  370. "O frabjous day! Callooh! Callay! "
  371. "He chortled in his joy. "
  372.  
  373. "Twas brillig, and the slithy toves "
  374. "Did gyre and gimble in the wabe: "
  375. "All mimsy were the borogoves, "
  376. "And the mome raths outgrabe."
  377.  
  378. ;
  379.  
  380. void loop() {
  381.  
  382. const char *m = jabberText;
  383.  
  384. while (*m) {
  385.  
  386.  
  387. for( uint8_t step=0; step<FONT_WIDTH+INTERCHAR_SPACE ; step++ ) { // step though each column of the 1st char for smooth scrolling
  388.  
  389. cli();
  390.  
  391. sendString( m , step , 0x00, 0x00 , 0x40 ); // Nice and not-too-bright blue hue
  392.  
  393. sei();
  394.  
  395.  
  396. }
  397.  
  398. m++;
  399.  
  400. }
  401.  
  402.  
  403. }
Advertisement
Add Comment
Please, Sign In to add comment