You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

181 lines
5.8KB

  1. // Copyright 2009 Olivier Gillet.
  2. //
  3. // Author: Olivier Gillet (ol.gillet@gmail.com)
  4. //
  5. // This program is free software: you can redistribute it and/or modify
  6. // it under the terms of the GNU General Public License as published by
  7. // the Free Software Foundation, either version 3 of the License, or
  8. // (at your option) any later version.
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. // You should have received a copy of the GNU General Public License
  14. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. //
  16. // -----------------------------------------------------------------------------
  17. //
  18. // Controller for an array of digital outputs behind a shift register. This
  19. // class maintains an internal array reflecting the status of each output. A
  20. // call to Output() writes the content of the array to a shift register, if the
  21. // content of the array has changed.
  22. //
  23. // The num_intensity_level template parameter allows basic PWM on the output
  24. // of the array. More specifically, each call to Output() will write a 0 or 1
  25. // depending on the "analog" level. This can be used for example to adjust
  26. // the brightness of a LED. More precisely, this is achieved in a PWM-like way
  27. // (we cycle N times through the array and at time i, we power only the outputs
  28. // with level above i/N).
  29. #ifndef AVRLIB_DEVICES_OUTPUT_ARRAY_H_
  30. #define AVRLIB_DEVICES_OUTPUT_ARRAY_H_
  31. #include <string.h>
  32. #include "avrlib/devices/shift_register.h"
  33. #include "avrlib/size_to_type.h"
  34. namespace avrlib {
  35. // A generic, not very efficient implementation, especially for small bit
  36. // depths.
  37. template<typename Latch, typename Clock, typename Data,
  38. uint8_t size = 16, uint8_t bit_depth = 1,
  39. DataOrder order = LSB_FIRST, bool safe = true>
  40. class OutputArray {
  41. public:
  42. OutputArray() { }
  43. typedef ShiftRegisterOutput<Latch, Clock, Data, size, order> Register;
  44. typedef typename DataTypeForSize<bit_depth>::Type Value;
  45. typedef typename DataTypeForSize<size>::Type Index;
  46. static inline void Init() {
  47. if (safe) {
  48. memset(values_, 0, sizeof(values_));
  49. cycle_ = 0;
  50. }
  51. Register::Init();
  52. }
  53. static inline void set_value(Index output_index, Value intensity) {
  54. values_[output_index] = intensity;
  55. }
  56. static inline Value value(Index output_index) {
  57. return values_[output_index];
  58. }
  59. static inline void ShiftOutByte(uint8_t v) {
  60. Register::ShiftOut(v);
  61. }
  62. static inline void Begin() {
  63. Register::Begin();
  64. }
  65. static inline void End() {
  66. Register::End();
  67. }
  68. static inline void Clear() { memset(values_, 0, sizeof(values_)); }
  69. static inline void ShiftOut() {
  70. Index c = 0;
  71. Index bit = 1;
  72. for (Index i = 0; i < size; ++i) {
  73. if (values_[i] > cycle_ || values_[i] == ((1 << bit_depth) - 1)) {
  74. c |= bit;
  75. }
  76. bit <<= 1;
  77. }
  78. cycle_ = (cycle_ + 1) & ((1 << bit_depth) - 1);
  79. Register::ShiftOut(c);
  80. }
  81. static inline void Write() {
  82. Begin();
  83. ShiftOut();
  84. End();
  85. }
  86. private:
  87. static Value values_[size];
  88. static Value cycle_;
  89. DISALLOW_COPY_AND_ASSIGN(OutputArray);
  90. };
  91. template<typename Latch, typename Clock, typename Data,
  92. uint8_t size, uint8_t bit_depth, DataOrder order, bool safe>
  93. typename OutputArray<Latch, Clock, Data, size, bit_depth, order, safe>::Value
  94. OutputArray<Latch, Clock, Data, size, bit_depth, order, safe>::values_[size];
  95. template<typename Latch, typename Clock, typename Data,
  96. uint8_t size, uint8_t bit_depth, DataOrder order, bool safe>
  97. typename OutputArray<Latch, Clock, Data, size, bit_depth, order, safe>::Value
  98. OutputArray<Latch, Clock, Data, size, bit_depth, order, safe>::cycle_;
  99. // A specialization with only two states. In this case, we can write data to the
  100. // shift register only when a bit has changed in the array - there's no pseudo
  101. // PWM brightness modulation.
  102. template<typename Latch, typename Clock, typename Data,
  103. uint8_t size, DataOrder order, bool safe>
  104. class OutputArray<Latch, Clock, Data, size, 1, order, safe> {
  105. typedef ShiftRegisterOutput<Latch, Clock, Data, size, order> Register;
  106. public:
  107. typedef typename DataTypeForSize<size>::Type T;
  108. OutputArray() { }
  109. static inline void Init() {
  110. if (safe) {
  111. last_bits_ = 1;
  112. bits_ = 0;
  113. }
  114. Register::Init();
  115. }
  116. static inline void set_value(uint8_t output_index, uint8_t intensity) {
  117. T mask = T(1) << output_index;
  118. if (intensity) {
  119. bits_ |= mask;
  120. } else {
  121. bits_ &= ~mask;
  122. }
  123. }
  124. static inline void Clear() { bits_ = 0; }
  125. static inline uint8_t value(uint8_t output_index) {
  126. T mask = T(1) << output_index;
  127. return T(bits_ & mask) ? 1 : 0;
  128. }
  129. static inline void ShiftOutByte(uint8_t v) {
  130. Register::ShiftOut(v);
  131. }
  132. static inline void Begin() {
  133. Register::Begin();
  134. }
  135. static inline void End() {
  136. Register::End();
  137. }
  138. static inline void ShiftOut() {
  139. if (bits_ == last_bits_) {
  140. return;
  141. }
  142. Register::ShiftOut(bits_);
  143. last_bits_ = bits_;
  144. }
  145. static inline void Write() {
  146. Begin();
  147. ShiftOut();
  148. End();
  149. }
  150. private:
  151. static T bits_;
  152. static T last_bits_;
  153. DISALLOW_COPY_AND_ASSIGN(OutputArray);
  154. };
  155. template<typename Latch, typename Clock, typename Data,
  156. uint8_t size, DataOrder order, bool safe>
  157. typename OutputArray<Latch, Clock, Data, size, 1, order, safe>::T
  158. OutputArray<Latch, Clock, Data, size, 1, order, safe>::bits_;
  159. template<typename Latch, typename Clock, typename Data,
  160. uint8_t size, DataOrder order, bool safe>
  161. typename OutputArray<Latch, Clock, Data, size, 1, order, safe>::T
  162. OutputArray<Latch, Clock, Data, size, 1, order, safe>::last_bits_;
  163. } // namespace avrlib
  164. #endif // AVRLIB_DEVICES_OUTPUT_ARRAY_H_