-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathht1621.c
More file actions
141 lines (115 loc) · 3.94 KB
/
ht1621.c
File metadata and controls
141 lines (115 loc) · 3.94 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#include "ht1621.h"
#include "ht1621_port.h"
#include <string.h>
// Each command is 12 bits
#define CMD_SIZE_BITS 12
enum HT1621_MODE
{
HT1621_MODE_READ = 0x06, //< 0b110 - Read mode [NOT IMPLEMENTED]
HT1621_MODE_WRITE = 0x05, //< 0b101 - Write mode
HT1621_MODE_READ_MODIFY_WRITE = 0x05, //< 0b101 - Read modify write mode [NOT IMPLEMENTED]
HT1621_MODE_COMMAND = 0x04, //< 0b100 - Command mode
};
static void enable(uint8_t state)
{
// CS and WR active low, invert state
state = !(state == 1);
// Set CS pin, active low
HT1621_Port_SetCSPin(state);
#ifdef HT1621_USE_GPIO_INTERFACE
// Set WR pin, active low
HT1621_Port_SetWRPin(state);
#endif
}
static void transmit(uint8_t *data, size_t bits)
{
enable(1);
#if defined(HT1621_USE_GPIO_INTERFACE)
// Bit bang each bit in the buffer
for (uint16_t i = 0; i < bits; i++)
{
uint16_t byte_idx = i / 8;
int8_t bit_idx = 7 - (i % 8);
uint8_t val = (data[byte_idx] >> bit_idx) & 0x01;
HT1621_Port_SetDataPin(val ? 1 : 0);
HT1621_Port_DelayUS(3);
HT1621_Port_SetWRPin(0);
HT1621_Port_DelayUS(3);
HT1621_Port_SetWRPin(1);
}
#elif defined(HT1621_USE_SPI_INTERFACE)
// Round up to nearest byte
size_t bytes_to_transfer = (bits + 7) / 8;
HT1621_Port_SPITransmit(data, bytes_to_transfer);
#endif
enable(0);
}
void HT1621_Init(void)
{
// Set CS and WR high
enable(0);
// Initialise the port layer
HT1621_Port_Init();
}
/**
* @brief Write a command to the HT1621
*
* @protocol 0b[3 bits mode][8 bits of command][1 X bit]
* Packed into bytes as: [m0,m1,m2,c0,c1,c2,c3,c4][c5,c6,c7,x0,0,0,0,0]
* @param cmd Command to send
*/
void HT1621_WriteCommand(enum HT1621_CMD_CODE cmd)
{
// 16-bits buffer to send a command. We use 12 bits only
uint8_t cmd_buff[2];
cmd_buff[0] = (HT1621_MODE_COMMAND << 5) | (cmd >> 3);
cmd_buff[1] = cmd << 5;
transmit(cmd_buff, CMD_SIZE_BITS);
}
/**
* @brief Successive write to HT1621 starting at start_address
*
* @protocol 0b[3 bits mode][6 bits address][data nibble 1][data nibble 2]...[data nibble N]
* Packed into bytes as: [m0,m1,m2,a0,a1,a2,a3,a4,a5][a6,d0,d1,d2,d3,d4,d5,d6]...
* @param data Pointer to nibble data to send. Each nibble (4 bits) is stored in it's own byte.
* i.e. data[0] = nibble 0, data[1] = nibble 1, etc.
* @param start_address Starting address (Normally 0)
* @param num_nibbles Number of nibbles in data to send (Usually sizeof(data) / sizeof(data[0]))
*/
void HT1621_SuccessiveWrite(uint8_t *data, uint8_t start_address, size_t num_nibbles)
{
// Total bits = Mode[3] + Address[6] + Data[num_nibbles * 4]
const size_t HEADER_BITS = 9;
const size_t total_bits = (num_nibbles * 4) + HEADER_BITS;
const size_t total_bytes = (total_bits + 7) / 8;
uint8_t raw_data[total_bytes];
memset(raw_data, 0, sizeof(raw_data));
// Pack header first: [3-bit mode][6-bit address]
start_address &= 0x3F; // Ensure 6 bits
raw_data[0] = (HT1621_MODE_WRITE << 5) | (start_address >> 1);
raw_data[1] = (start_address << 7); // Bit 8 = LSB of address
// Write nibbles starting at bit 9
for (size_t i = 0; i < num_nibbles; ++i)
{
uint8_t nibble = data[i] & 0x0F;
size_t bit_offset = HEADER_BITS + (i * 4);
size_t byte_idx = bit_offset / 8;
size_t bit_pos = bit_offset % 8;
// Write nibble across byte boundary if needed
if (bit_pos <= 4)
{
// Nibble fits in current byte
raw_data[byte_idx] |= (nibble << (4 - bit_pos));
}
else
{
// Nibble spans two bytes
raw_data[byte_idx] |= (nibble >> (bit_pos - 4));
if (byte_idx + 1 < total_bytes)
{
raw_data[byte_idx + 1] |= (nibble << (12 - bit_pos));
}
}
}
transmit(raw_data, total_bits);
}