pca9685.rs 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. use core::mem::size_of;
  2. use field_offset::offset_of;
  3. use stm32l4xx_hal::prelude::_embedded_hal_blocking_i2c_Write;
  4. use tock_registers::{
  5. interfaces::{ReadWriteable, Readable, Writeable},
  6. register_bitfields, register_structs,
  7. registers::InMemoryRegister,
  8. };
  9. const MAX_BRIGHTNESS: u32 = 4096;
  10. register_bitfields![
  11. u8,
  12. MODE_1 [
  13. ALLCALL 0,
  14. SUB3 1,
  15. SUB2 2,
  16. SUB1 3,
  17. SLEEP 4,
  18. AI 5,
  19. EXTCLK 6,
  20. RESTART 7,
  21. ],
  22. MODE_2 [
  23. OUTNE OFFSET(0) NUMBITS(2) [],
  24. OUTDRV OFFSET(2) NUMBITS(1) [],
  25. OCH OFFSET(3) NUMBITS(1) [],
  26. INVRT OFFSET(4) NUMBITS(1) [],
  27. ],
  28. ];
  29. register_bitfields![
  30. u32,
  31. LED_CTRL [
  32. On OFFSET(0) NUMBITS(12) [],
  33. On_Full OFFSET(12) NUMBITS(1) [],
  34. Off OFFSET(16) NUMBITS(12) [],
  35. Off_Full OFFSET(28) NUMBITS(1) [],
  36. ],
  37. ];
  38. register_structs! {
  39. #[repr(packed(1))]
  40. Pca9685Registers {
  41. (0x00 => mode1: InMemoryRegister<u8, MODE_1::Register>),
  42. (0x01 => mode2: InMemoryRegister<u8, MODE_2::Register>),
  43. (0x02 => subaddress1: InMemoryRegister<u8>),
  44. (0x03 => subaddress2: InMemoryRegister<u8>),
  45. (0x04 => subaddress3: InMemoryRegister<u8>),
  46. (0x05 => allcalladdr: InMemoryRegister<u8>),
  47. (0x06 => led: [InMemoryRegister<u32, LED_CTRL::Register>; 16]),
  48. (0x46 => _reserved),
  49. (0xFA => all_led: InMemoryRegister<u32, LED_CTRL::Register>),
  50. (0xFE => prescale: InMemoryRegister<u8>),
  51. (0xFF => testmode: InMemoryRegister<u8>),
  52. (0x100 => @END),
  53. }
  54. }
  55. #[test]
  56. fn offset_test() {
  57. assert_eq!(offset_of!(Pca9685Registers => led).get_byte_offset(), 0x6);
  58. assert_eq!(offset_of!(Pca9685Registers => all_led).get_byte_offset(), 0xFA);
  59. assert_eq!(offset_of!(Pca9685Registers => prescale).get_byte_offset(), 0xFE);
  60. assert_eq!(offset_of!(Pca9685Registers => testmode).get_byte_offset(), 0xFF);
  61. }
  62. pub fn init(address: u8, i2c: &mut impl _embedded_hal_blocking_i2c_Write) {
  63. let mode1_reg: InMemoryRegister<u8, MODE_1::Register> = InMemoryRegister::new(0);
  64. let mode2_reg: InMemoryRegister<u8, MODE_2::Register> = InMemoryRegister::new(0);
  65. // Turn on autoincrement
  66. // Start disabled
  67. // Enable response to all call address
  68. mode1_reg.modify(MODE_1::AI::SET + MODE_1::SLEEP::SET + MODE_1::ALLCALL::SET);
  69. // Configure output for totem pole drive
  70. mode2_reg.modify(MODE_2::OUTDRV::SET);
  71. let buffer: [u8; 3] = [
  72. offset_of!(Pca9685Registers => mode1).get_byte_offset() as u8,
  73. mode1_reg.get(),
  74. mode2_reg.get(),
  75. ];
  76. match i2c.write(address, &buffer) {
  77. Ok(_) => (),
  78. Err(_) => panic!(),
  79. }
  80. let prescale_reg: InMemoryRegister<u8> = InMemoryRegister::new(0);
  81. // Set PWM frequency to 1526Hz
  82. prescale_reg.set(0x03);
  83. let buffer: [u8; 2] = [
  84. offset_of!(Pca9685Registers => prescale).get_byte_offset() as u8,
  85. prescale_reg.get(),
  86. ];
  87. match i2c.write(address, &buffer) {
  88. Ok(_) => (),
  89. Err(_) => panic!(),
  90. }
  91. // Zero
  92. let mut buffer: [u8; 65] = [0; 65];
  93. buffer[0] = offset_of!(Pca9685Registers => led).get_byte_offset() as u8;
  94. match i2c.write(address, &buffer) {
  95. Ok(_) => (),
  96. Err(_) => panic!(),
  97. }
  98. // Re-enable outputs
  99. mode1_reg.modify(MODE_1::SLEEP::CLEAR);
  100. let buffer: [u8; 2] = [
  101. offset_of!(Pca9685Registers => mode1).get_byte_offset() as u8,
  102. mode1_reg.get(),
  103. ];
  104. match i2c.write(address, &buffer) {
  105. Ok(_) => (),
  106. Err(_) => panic!(),
  107. }
  108. }
  109. pub fn set_digit(
  110. address: u8,
  111. i2c: &mut impl _embedded_hal_blocking_i2c_Write,
  112. pin: usize,
  113. pwm_start: u32,
  114. pwm_end: u32,
  115. ) {
  116. let led_reg: InMemoryRegister<u32, LED_CTRL::Register> = InMemoryRegister::new(0);
  117. led_reg.modify(LED_CTRL::On.val(pwm_start));
  118. led_reg.modify(LED_CTRL::Off.val(pwm_end));
  119. if pwm_end == 0 {
  120. led_reg.modify(LED_CTRL::Off_Full::SET)
  121. } else if pwm_end >= MAX_BRIGHTNESS {
  122. led_reg.modify(LED_CTRL::On_Full::SET)
  123. }
  124. let buffer: [u8; 5] = [
  125. (offset_of!(Pca9685Registers => led).get_byte_offset() + size_of::<u32>() * pin) as u8,
  126. led_reg.get().to_le_bytes()[0],
  127. led_reg.get().to_le_bytes()[1],
  128. led_reg.get().to_le_bytes()[2],
  129. led_reg.get().to_le_bytes()[3],
  130. ];
  131. match i2c.write(address, &buffer) {
  132. Ok(_) => (),
  133. Err(_) => panic!(),
  134. }
  135. }