Bez tytułu

z Mammoth Camel, 1 dzień temu, napisane w C, wyświetlone 6 razy. [paste_expire] 10 miesiące.
URL https://pastebin.k4be.pl/view/41c28976 Udostępnij
Pobierz wklejkę lub Pokaż surowy tekst
  1. #include <string.h>
  2. #include <avr/io.h>
  3. #include <avr/pgmspace.h>
  4. #include <util/delay.h>
  5. #include "pt6524.h"
  6. #include "spi.h"
  7.  
  8. // PT6524 Command/Address
  9. // Datasheet specifies 41H, sent with DORD=1 (LSB-first)
  10. // Hardware automatically reverses 0x41 to 0x82 on the wire
  11. #define PT6524_ADDRESS  0x41
  12.  
  13. // Control bits
  14. #define CTRL_BU   (1 << 0)  // Normal/Power Saving Mode (0=Normal, 1=Power Saving)
  15. #define CTRL_SC   (1 << 1)  // Segment ON/OFF (0=ON, 1=OFF)
  16. #define CTRL_DR   (1 << 2)  // Bias Drive (0=1/3 bias, 1=1/2 bias)
  17. #define CTRL_P3   (1 << 3)  // Port select bit 3
  18. #define CTRL_P2   (1 << 4)  // Port select bit 2
  19. #define CTRL_P1   (1 << 5)  // Port select bit 1
  20. #define CTRL_P0   (1 << 6)  // Port select bit 0
  21. #define CTRL_CU   (1 << 7)  // Current drain control (0=Normal, 1=Low)
  22.  
  23. // Display framebuffer - stores segment states
  24. // Each bit represents one segment/COM intersection
  25. // Organized as: D1, D2, D3, D4, D5, D6, ... D160
  26. // Where D1=SG1:COM1, D2=SG1:COM2, D3=SG1:COM3, D4=SG1:COM4,
  27. //       D5=SG2:COM1, D6=SG2:COM2, etc.
  28. static uint8_t framebuffer[(PT6524_TOTAL_SEGMENTS * PT6524_TOTAL_COMS + 7) / 8];
  29.  
  30. // Initialize PT6524 LCD driver
  31. void pt6524_init(void) {
  32.         // Set DISP_ON low BEFORE configuring as output
  33.         DISP_ON_PORT &= ~DISP_ON;
  34.         DISP_ON_DDR |= DISP_ON;
  35.  
  36.     // Initialize SPI
  37.     spi_init();
  38.  
  39.     // Keep display off during initialization
  40.     DISP_ON_LOW();
  41.  
  42.     pt6524_clear_all();
  43.  
  44.     // Enable display
  45.     DISP_ON_HIGH();
  46. }
  47.  
  48. // Set a specific segment on or off
  49. // address: Linear address (0 to PT6524_MAX_ADDRESS-1)
  50. //          Address 0 = SG1:COM1, 1 = SG1:COM2, 2 = SG1:COM3, 3 = SG1:COM4,
  51. //          Address 4 = SG2:COM1, 5 = SG2:COM2, etc.
  52. // state: 0 = off, non-zero = on
  53. void pt6524_set_segment(uint8_t address, uint8_t state) {
  54.     // Validate address against actual framebuffer size
  55.     if (address >= PT6524_MAX_ADDRESS)
  56.         return;
  57.  
  58.     // Calculate bit position in framebuffer
  59.     // Linear address directly maps to bit index in framebuffer
  60.     uint8_t byte_pos = address / 8;
  61.     uint8_t bit_pos = address % 8;
  62.  
  63.     // Set or clear the bit
  64.     if (state) {
  65.         framebuffer[byte_pos] |= (1 << bit_pos);
  66.     } else {
  67.         framebuffer[byte_pos] &= ~(1 << bit_pos);
  68.     }
  69. }
  70.  
  71. // Clear all segments
  72. void pt6524_clear_all(void) {
  73.     memset(framebuffer, 0, sizeof(framebuffer));
  74. }
  75.  
  76. // Get direct access to framebuffer for efficient bulk updates
  77. uint8_t* pt6524_get_framebuffer(void) {
  78.     return framebuffer;
  79. }
  80.  
  81. // Write a single byte to framebuffer
  82. void pt6524_write_byte(uint8_t byte_index, uint8_t value) {
  83.     if (byte_index < sizeof(framebuffer))
  84.         framebuffer[byte_index] = value;
  85. }
  86.  
  87. // Write a block of bytes to framebuffer
  88. void pt6524_write_block(uint8_t byte_index, const uint8_t* data, uint8_t length) {
  89.     if (byte_index + length <= sizeof(framebuffer))
  90.         memcpy(&framebuffer[byte_index], data, length);
  91. }
  92.  
  93. #define DATA_BITS_PER_BLOCK 52
  94.  
  95. static inline void pt6524_send_block(uint8_t dir_bits, uint16_t start_addr) {
  96.     const uint8_t control = 0x00; // DR=0 for 1/3 bias
  97.  
  98.     _delay_us(.16);
  99.     spi_write(PT6524_ADDRESS);
  100.     CE_HIGH();
  101.  
  102.     uint8_t data_payload[7] = {0}; // 52 bits = 6.5 bytes
  103.  
  104.     // Determine how many bits to send in this block
  105.     uint16_t bits_to_send = PT6524_MAX_ADDRESS - start_addr;
  106.     if (bits_to_send > DATA_BITS_PER_BLOCK) {
  107.         bits_to_send = DATA_BITS_PER_BLOCK;
  108.     }
  109.  
  110.     // Prepare data payload from framebuffer
  111.     uint16_t start_byte_idx = start_addr / 8;
  112.     uint8_t start_bit_offset = start_addr % 8;
  113.     uint16_t current_byte_idx = start_byte_idx;
  114.     uint16_t bits_prepared = 0;
  115.  
  116.     for (uint8_t i = 0; i < sizeof(data_payload); i++) {
  117.         if (bits_prepared >= bits_to_send) {
  118.             break;
  119.         }
  120.  
  121.         uint8_t data_byte = 0;
  122.         if (start_bit_offset == 0) {
  123.             if (current_byte_idx < sizeof(framebuffer)) {
  124.                 data_byte = framebuffer[current_byte_idx];
  125.             }
  126.         } else {
  127.             if (current_byte_idx < sizeof(framebuffer)) {
  128.                 data_byte = (framebuffer[current_byte_idx] >> start_bit_offset);
  129.             }
  130.             if (current_byte_idx + 1 < sizeof(framebuffer)) {
  131.                 data_byte |= (framebuffer[current_byte_idx + 1] << (8 - start_bit_offset));
  132.             }
  133.         }
  134.        
  135.         uint16_t bits_left_to_prepare = bits_to_send - bits_prepared;
  136.         if (bits_left_to_prepare < 8) {
  137.             data_byte &= (1 << bits_left_to_prepare) - 1;
  138.         }
  139.  
  140.         data_payload[i] = data_byte;
  141.         bits_prepared += 8;
  142.         current_byte_idx++;
  143.     }
  144.  
  145.     // Write data payload bytes 1-6
  146.     for (uint8_t i = 0; i < 6; i++) {
  147.         spi_write(data_payload[i]);
  148.     }
  149.  
  150.     uint8_t byte7 = data_payload[6];
  151.     uint8_t byte8 = 0;
  152.  
  153.     // Prepare bytes 7 and 8 which contain last data nibble and control bits
  154.     switch (dir_bits) {
  155.         case 0: // dir=00
  156.             byte7 |= ((control & CTRL_CU) ? 0x40 : 0) | ((control & CTRL_P0) ? 0x80 : 0);
  157.             byte8 = ((control & CTRL_P1) ? 0x01 : 0) | ((control & CTRL_P2) ? 0x02 : 0) |
  158.                     ((control & CTRL_P3) ? 0x04 : 0) | ((control & CTRL_DR) ? 0x08 : 0) |
  159.                     ((control & CTRL_SC) ? 0x10 : 0) | ((control & CTRL_BU) ? 0x20 : 0);
  160.             break;
  161.         case 1: // dir=01
  162.             byte8 = 0x40;
  163.             break;
  164.         case 2: // dir=10
  165.             byte8 = 0x80;
  166.             break;
  167.         case 3: // dir=11
  168.             byte8 = 0xC0;
  169.             break;
  170.     }
  171.     spi_write(byte7);
  172.     spi_write(byte8);
  173.  
  174.     CE_LOW();
  175. }
  176.  
  177. // Update the display by sending framebuffer data via SPI
  178. // This function calls the pt6524_send_block helper for each required transaction.
  179. // With compiler optimizations, this will be expanded into a series of efficient,
  180. // hardcoded SPI writes specific to the chosen PT6524_MAX_ADDRESS.
  181. void pt6524_update_display(void) {
  182. #if PT6524_MAX_ADDRESS > (DATA_BITS_PER_BLOCK * 0)
  183.     pt6524_send_block(0, (DATA_BITS_PER_BLOCK * 0));
  184. #endif
  185. #if PT6524_MAX_ADDRESS > (DATA_BITS_PER_BLOCK * 1)
  186.     pt6524_send_block(1, (DATA_BITS_PER_BLOCK * 1));
  187. #endif
  188. #if PT6524_MAX_ADDRESS > (DATA_BITS_PER_BLOCK * 2)
  189.     pt6524_send_block(2, (DATA_BITS_PER_BLOCK * 2));
  190. #endif
  191. #if PT6524_MAX_ADDRESS > (DATA_BITS_PER_BLOCK * 3)
  192.     pt6524_send_block(3, (DATA_BITS_PER_BLOCK * 3));
  193. #endif
  194. }

odpowiedź "Bez tytułu"

Tutaj możesz odpowiedzieć na wklejkę z góry

captcha