pca9685.cpp 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. #include "mbed.h"
  2. #include "main.h"
  3. #include "pca9685.h"
  4. DigitalOut PCA9685_PWM_nEN(PA_7);
  5. DigitalOut PCA9685_VIN_EN(PB_1);
  6. AnalogOut PCA9685_VIN(PA_5);
  7. void PCA9685_Init(void) {
  8. PCA9685_REGS regs = {0};
  9. // Power up PCA9685 at full voltage with outputs disabled
  10. PCA9685_VIN.write(1);
  11. PCA9685_VIN_EN.write(1);
  12. PCA9685_PWM_nEN.write(1);
  13. regs.MODE1.AI = 1; // Turn on autoincrement
  14. regs.MODE1.SLEEP = 1; // Start disabled
  15. regs.MODE1.ALLCALL = 1; // Enable response to all call address
  16. regs.MODE2.OUTDRV = 1; // Configure output for totem pole drive
  17. I2C_Write(PCA9685_All_Call, FIELD_OFFSET(PCA9685_REGS, MODE1),
  18. regs.AS_BYTE + FIELD_OFFSET(PCA9685_REGS, MODE1),
  19. FIELD_SIZE_THROUGH(PCA9685_REGS, MODE1, MODE2));
  20. regs.PRE_SCALE = 0x03; // Set PWM frequency to 1526Hz
  21. I2C_Write(PCA9685_All_Call, FIELD_OFFSET(PCA9685_REGS, PRE_SCALE),
  22. regs.AS_BYTE + FIELD_OFFSET(PCA9685_REGS, PRE_SCALE),
  23. FIELD_SIZE_THROUGH(PCA9685_REGS, PRE_SCALE, PRE_SCALE));
  24. PCA9685_SetDot(0);
  25. for (int i = 0; i < 4; i++) {
  26. for (int j = 0; j < 10; j++) {
  27. PCA9685_SetDigit(i, j, 0);
  28. }
  29. }
  30. regs.MODE1.SLEEP = 0; // Re-enable outputs
  31. I2C_Write(PCA9685_All_Call, FIELD_OFFSET(PCA9685_REGS, MODE1),
  32. regs.AS_BYTE + FIELD_OFFSET(PCA9685_REGS, MODE1),
  33. FIELD_SIZE_THROUGH(PCA9685_REGS, MODE1, MODE1));
  34. // Enable outputs after configuration has been completed
  35. PCA9685_PWM_nEN.write(0);
  36. }
  37. void PCA9685_SetVoltage(float Percent) {
  38. Percent = Percent * 0.6;
  39. PCA9685_VIN.write(Percent);
  40. }
  41. void PCA9685_SetDigit(int Tube, int Digit, int Brightness) {
  42. LED_CTRL reg = {0};
  43. if (Brightness >= PCA9685_Max_Brightness) {
  44. reg.ON_FULL = 1;
  45. } else if (Brightness == 0) {
  46. reg.OFF_FULL = 1;
  47. } else {
  48. reg.OFF = Brightness;
  49. }
  50. I2C_Write(Tube_Mapping[Tube][Digit][MAP_ADDR],
  51. FIELD_OFFSET(PCA9685_REGS, LED0) + (Tube_Mapping[Tube][Digit][MAP_PIN] * sizeof(LED_CTRL)),
  52. reg.AS_BYTE, sizeof(LED_CTRL));
  53. }
  54. void PCA9685_SetDigitPwm(int Tube, int Digit, int StartPwm, int EndPwm) {
  55. LED_CTRL reg = {0};
  56. reg.ON = StartPwm;
  57. reg.OFF = EndPwm;
  58. if (EndPwm - StartPwm >= PCA9685_Max_Brightness) {
  59. reg.ON_FULL = 1;
  60. } else if (EndPwm == 0) {
  61. reg.OFF_FULL = 1;
  62. }
  63. I2C_Write(Tube_Mapping[Tube][Digit][MAP_ADDR],
  64. FIELD_OFFSET(PCA9685_REGS, LED0) + (Tube_Mapping[Tube][Digit][MAP_PIN] * sizeof(LED_CTRL)),
  65. reg.AS_BYTE, sizeof(LED_CTRL));
  66. }
  67. void PCA9685_SetDot(int Brightness) {
  68. LED_CTRL reg = {0};
  69. if (Brightness >= PCA9685_Max_Brightness) {
  70. reg.ON_FULL = 1;
  71. } else if (Brightness == 0) {
  72. reg.OFF_FULL = 1;
  73. } else {
  74. reg.OFF = Brightness;
  75. }
  76. I2C_Write(TUBE_DOT_ADDR, FIELD_OFFSET(PCA9685_REGS, TUBE_DOT_PIN), reg.AS_BYTE, sizeof(LED_CTRL));
  77. }
  78. void PCA9685_SetDotPwm(int StartPwm, int EndPwm) {
  79. LED_CTRL reg = {0};
  80. reg.ON = StartPwm;
  81. reg.OFF = EndPwm;
  82. if (EndPwm - StartPwm >= PCA9685_Max_Brightness) {
  83. reg.ON_FULL = 1;
  84. } else if (EndPwm == 0) {
  85. reg.OFF_FULL = 1;
  86. } else if (EndPwm >= PCA9685_Max_Brightness) {
  87. reg.OFF = 0xFFF;
  88. }
  89. I2C_Write(TUBE_DOT_ADDR, FIELD_OFFSET(PCA9685_REGS, TUBE_DOT_PIN), reg.AS_BYTE, sizeof(LED_CTRL));
  90. }
  91. void PCA9685_EnableOutput(bool Enabled) {
  92. if (Enabled) {
  93. PCA9685_PWM_nEN.write(0);
  94. } else {
  95. PCA9685_PWM_nEN.write(1);
  96. }
  97. }