lp5562.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. #include "lp5562.h"
  2. #include "lp5562_reg.h"
  3. #include <furi_hal.h>
  4. #include <stdio.h>
  5. void lp5562_reset(FuriHalI2cBusHandle* handle) {
  6. Reg0D_Reset reg = {.value = 0xFF};
  7. furi_hal_i2c_write_reg_8(handle, LP5562_ADDRESS, 0x0D, *(uint8_t*)&reg, LP5562_I2C_TIMEOUT);
  8. }
  9. void lp5562_configure(FuriHalI2cBusHandle* handle) {
  10. Reg08_Config config = {.INT_CLK_EN = true, .PS_EN = true, .PWM_HF = true};
  11. furi_hal_i2c_write_reg_8(handle, LP5562_ADDRESS, 0x08, *(uint8_t*)&config, LP5562_I2C_TIMEOUT);
  12. Reg70_LedMap map = {
  13. .red = EngSelectI2C,
  14. .green = EngSelectI2C,
  15. .blue = EngSelectI2C,
  16. .white = EngSelectI2C,
  17. };
  18. furi_hal_i2c_write_reg_8(handle, LP5562_ADDRESS, 0x70, *(uint8_t*)&map, LP5562_I2C_TIMEOUT);
  19. }
  20. void lp5562_enable(FuriHalI2cBusHandle* handle) {
  21. Reg00_Enable reg = {.CHIP_EN = true, .LOG_EN = true};
  22. furi_hal_i2c_write_reg_8(handle, LP5562_ADDRESS, 0x00, *(uint8_t*)&reg, LP5562_I2C_TIMEOUT);
  23. //>488μs delay is required after writing to 0x00 register, otherwise program engine will not work
  24. delay_us(500);
  25. }
  26. void lp5562_set_channel_current(FuriHalI2cBusHandle* handle, LP5562Channel channel, uint8_t value) {
  27. uint8_t reg_no;
  28. if(channel == LP5562ChannelRed) {
  29. reg_no = LP5562_CHANNEL_RED_CURRENT_REGISTER;
  30. } else if(channel == LP5562ChannelGreen) {
  31. reg_no = LP5562_CHANNEL_GREEN_CURRENT_REGISTER;
  32. } else if(channel == LP5562ChannelBlue) {
  33. reg_no = LP5562_CHANNEL_BLUE_CURRENT_REGISTER;
  34. } else if(channel == LP5562ChannelWhite) {
  35. reg_no = LP5562_CHANNEL_WHITE_CURRENT_REGISTER;
  36. } else {
  37. return;
  38. }
  39. furi_hal_i2c_write_reg_8(handle, LP5562_ADDRESS, reg_no, value, LP5562_I2C_TIMEOUT);
  40. }
  41. void lp5562_set_channel_value(FuriHalI2cBusHandle* handle, LP5562Channel channel, uint8_t value) {
  42. uint8_t reg_no;
  43. if(channel == LP5562ChannelRed) {
  44. reg_no = LP5562_CHANNEL_RED_VALUE_REGISTER;
  45. } else if(channel == LP5562ChannelGreen) {
  46. reg_no = LP5562_CHANNEL_GREEN_VALUE_REGISTER;
  47. } else if(channel == LP5562ChannelBlue) {
  48. reg_no = LP5562_CHANNEL_BLUE_VALUE_REGISTER;
  49. } else if(channel == LP5562ChannelWhite) {
  50. reg_no = LP5562_CHANNEL_WHITE_VALUE_REGISTER;
  51. } else {
  52. return;
  53. }
  54. furi_hal_i2c_write_reg_8(handle, LP5562_ADDRESS, reg_no, value, LP5562_I2C_TIMEOUT);
  55. }
  56. uint8_t lp5562_get_channel_value(FuriHalI2cBusHandle* handle, LP5562Channel channel) {
  57. uint8_t reg_no;
  58. uint8_t value;
  59. if(channel == LP5562ChannelRed) {
  60. reg_no = LP5562_CHANNEL_RED_VALUE_REGISTER;
  61. } else if(channel == LP5562ChannelGreen) {
  62. reg_no = LP5562_CHANNEL_GREEN_VALUE_REGISTER;
  63. } else if(channel == LP5562ChannelBlue) {
  64. reg_no = LP5562_CHANNEL_BLUE_VALUE_REGISTER;
  65. } else if(channel == LP5562ChannelWhite) {
  66. reg_no = LP5562_CHANNEL_WHITE_VALUE_REGISTER;
  67. } else {
  68. return 0;
  69. }
  70. furi_hal_i2c_read_reg_8(handle, LP5562_ADDRESS, reg_no, &value, LP5562_I2C_TIMEOUT);
  71. return value;
  72. }
  73. static void
  74. lp5562_set_channel_src(FuriHalI2cBusHandle* handle, LP5562Channel channel, LP5562Engine src) {
  75. uint8_t reg_val = 0;
  76. uint8_t bit_offset = 0;
  77. if(channel == LP5562ChannelRed) {
  78. bit_offset = 4;
  79. } else if(channel == LP5562ChannelGreen) {
  80. bit_offset = 2;
  81. } else if(channel == LP5562ChannelBlue) {
  82. bit_offset = 0;
  83. } else if(channel == LP5562ChannelWhite) {
  84. bit_offset = 6;
  85. } else {
  86. return;
  87. }
  88. furi_hal_i2c_read_reg_8(handle, LP5562_ADDRESS, 0x70, &reg_val, LP5562_I2C_TIMEOUT);
  89. reg_val &= ~(0x3 << bit_offset);
  90. reg_val |= ((src & 0x03) << bit_offset);
  91. furi_hal_i2c_write_reg_8(handle, LP5562_ADDRESS, 0x70, reg_val, LP5562_I2C_TIMEOUT);
  92. }
  93. void lp5562_execute_program(
  94. FuriHalI2cBusHandle* handle,
  95. LP5562Engine eng,
  96. LP5562Channel ch,
  97. uint16_t* program) {
  98. if((eng < LP5562Engine1) || (eng > LP5562Engine3)) return;
  99. uint8_t reg_val = 0;
  100. uint8_t bit_offset = 0;
  101. uint8_t enable_reg = 0;
  102. // Read old value of enable register
  103. furi_hal_i2c_read_reg_8(handle, LP5562_ADDRESS, 0x00, &enable_reg, LP5562_I2C_TIMEOUT);
  104. // Engine configuration
  105. bit_offset = (3 - eng) * 2;
  106. furi_hal_i2c_read_reg_8(handle, LP5562_ADDRESS, 0x01, &reg_val, LP5562_I2C_TIMEOUT);
  107. reg_val &= ~(0x3 << bit_offset);
  108. reg_val |= (0x01 << bit_offset); // load
  109. furi_hal_i2c_write_reg_8(handle, LP5562_ADDRESS, 0x01, reg_val, LP5562_I2C_TIMEOUT);
  110. delay_us(100);
  111. // Program load
  112. for(uint8_t i = 0; i < 16; i++) {
  113. // Program words are big-endian, so reverse byte order before loading
  114. program[i] = __REV16(program[i]);
  115. }
  116. furi_hal_i2c_write_mem(
  117. handle,
  118. LP5562_ADDRESS,
  119. 0x10 + (0x20 * (eng - 1)),
  120. (uint8_t*)program,
  121. 16 * 2,
  122. LP5562_I2C_TIMEOUT);
  123. // Program start
  124. bit_offset = (3 - eng) * 2;
  125. furi_hal_i2c_read_reg_8(handle, LP5562_ADDRESS, 0x01, &reg_val, LP5562_I2C_TIMEOUT);
  126. reg_val &= ~(0x3 << bit_offset);
  127. reg_val |= (0x02 << bit_offset); // run
  128. furi_hal_i2c_write_reg_8(handle, LP5562_ADDRESS, 0x01, reg_val, LP5562_I2C_TIMEOUT);
  129. // Switch output to Execution Engine
  130. lp5562_set_channel_src(handle, ch, eng);
  131. enable_reg &= ~(0x3 << bit_offset);
  132. enable_reg |= (0x02 << bit_offset); // run
  133. furi_hal_i2c_write_reg_8(handle, LP5562_ADDRESS, 0x00, enable_reg, LP5562_I2C_TIMEOUT);
  134. }
  135. void lp5562_execute_ramp(
  136. FuriHalI2cBusHandle* handle,
  137. LP5562Engine eng,
  138. LP5562Channel ch,
  139. uint8_t val_start,
  140. uint8_t val_end,
  141. uint16_t time) {
  142. if(val_start == val_end) return;
  143. // Temporary switch to constant value from register
  144. lp5562_set_channel_src(handle, ch, LP5562Direct);
  145. // Prepare command sequence
  146. uint16_t program[16];
  147. uint8_t diff = (val_end > val_start) ? (val_end - val_start) : (val_start - val_end);
  148. uint16_t time_step = time * 2 / diff;
  149. uint8_t prescaller = 0;
  150. if(time_step > 0x3F) {
  151. time_step /= 32;
  152. prescaller = 1;
  153. }
  154. if(time_step == 0) {
  155. time_step = 1;
  156. } else if(time_step > 0x3F)
  157. time_step = 0x3F;
  158. program[0] = 0x4000 | val_start; // Set PWM
  159. if(val_end > val_start) {
  160. program[1] = (prescaller << 14) | (time_step << 8) | ((diff / 2) & 0x7F); // Ramp Up
  161. } else {
  162. program[1] = (prescaller << 14) | (time_step << 8) | 0x80 |
  163. ((diff / 2) & 0x7F); // Ramp Down
  164. }
  165. program[2] = 0xA001 | ((2 - 1) << 7); // Loop to step 1, repeat twice to get full 8-bit scale
  166. program[3] = 0xC000; // End
  167. // Execute program
  168. lp5562_execute_program(handle, eng, LP5562ChannelWhite, program);
  169. // Write end value to register
  170. lp5562_set_channel_value(handle, ch, val_end);
  171. }