Firmware SDK
twr_sc16is740.c
1 #include <twr_sc16is740.h>
2 
3 #define _TWR_SC16IS740_CRYSTCAL_FREQ (13560000UL)
4 #define _TWR_SC16IS740_FIFO_SIZE 64
5 #define _TWR_SC16IS740_REG_RHR 0x00
6 #define _TWR_SC16IS740_REG_THR 0x00
7 #define _TWR_SC16IS740_REG_IER 0x01 << 3
8 #define _TWR_SC16IS740_REG_FCR 0x02 << 3
9 #define _TWR_SC16IS740_REG_LCR 0x03 << 3
10 #define _TWR_SC16IS740_REG_MCR 0x04 << 3
11 #define _TWR_SC16IS740_BIT_FIFO_ENABLE 0x01
12 #define _TWR_SC16IS740_REG_SPR 0x07 << 3
13 #define _TWR_SC16IS740_REG_TXLVL 0x08 << 3
14 #define _TWR_SC16IS740_REG_RXLVL 0x09 << 3
15 #define _TWR_SC16IS740_REG_IOCONTROL 0x0E << 3
16 #define _TWR_SC16IS740_BIT_UART_SOFTWARE_RESET 0x08
17 #define _TWR_SC16IS740_LCR_SPECIAL_REGISTER 0x80
18 #define _TWR_SC16IS740_SPECIAL_REG_DLL 0x00 << 3
19 #define _TWR_SC16IS740_SPECIAL_REG_DLH 0x01 << 3
20 #define _TWR_SC16IS740_LCR_SPECIAL_ENHANCED_REGISTER 0xBF
21 #define _TWR_SC16IS740_ENHANCED_REG_EFR 0x02 << 3
22 
23 bool twr_sc16is740_init(twr_sc16is740_t *self, twr_i2c_channel_t i2c_channel, uint8_t i2c_address)
24 {
25  memset(self, 0, sizeof(*self));
26 
27  self->_i2c_channel = i2c_channel;
28  self->_i2c_address = i2c_address;
29 
30  twr_i2c_init(self->_i2c_channel, TWR_I2C_SPEED_400_KHZ);
31 
32  // Switch to access Special register
33  if (!twr_i2c_memory_write_8b(self->_i2c_channel, self->_i2c_address, _TWR_SC16IS740_REG_LCR, _TWR_SC16IS740_LCR_SPECIAL_REGISTER))
34  {
35  return false;
36  }
37 
38  if (!twr_i2c_memory_write_8b(self->_i2c_channel, self->_i2c_address, _TWR_SC16IS740_SPECIAL_REG_DLL, 0x58))
39  {
40  return false;
41  }
42 
43  if (!twr_i2c_memory_write_8b(self->_i2c_channel, self->_i2c_address, _TWR_SC16IS740_SPECIAL_REG_DLH, 0x00))
44  {
45  return false;
46  }
47 
48  // Switch to access Enhanced register
49  if (!twr_i2c_memory_write_8b(self->_i2c_channel, self->_i2c_address, _TWR_SC16IS740_REG_LCR, _TWR_SC16IS740_LCR_SPECIAL_ENHANCED_REGISTER))
50  {
51  return false;
52  }
53 
54  if (!twr_i2c_memory_write_8b(self->_i2c_channel, self->_i2c_address, _TWR_SC16IS740_ENHANCED_REG_EFR, 0x10))
55  {
56  return false;
57  }
58 
59  // No break, no parity, 2 stop bits, 8 data bits
60  if (!twr_i2c_memory_write_8b(self->_i2c_channel, self->_i2c_address, _TWR_SC16IS740_REG_LCR, 0x07))
61  {
62  return false;
63  }
64 
65  // FIFO enabled, FIFO reset RX and TX
66  if (!twr_i2c_memory_write_8b(self->_i2c_channel, self->_i2c_address, _TWR_SC16IS740_REG_FCR, 0x07))
67  {
68  return false;
69  }
70 
71  if (!twr_i2c_memory_write_8b(self->_i2c_channel, self->_i2c_address, _TWR_SC16IS740_REG_IER, 0x11))
72  {
73  return false;
74  }
75 
76  return true;
77 }
78 
79 bool twr_sc16is740_reset_fifo(twr_sc16is740_t *self, twr_sc16is740_fifo_t fifo)
80 {
81  uint8_t register_fcr;
82 
83  register_fcr = fifo | _TWR_SC16IS740_BIT_FIFO_ENABLE;
84 
85  return twr_i2c_memory_write_8b(self->_i2c_channel, self->_i2c_address, _TWR_SC16IS740_REG_FCR, register_fcr);
86 }
87 
88 bool twr_sc16is740_get_spaces_available(twr_sc16is740_t *self, size_t *spaces_available)
89 {
90  uint8_t value;
91 
92  if (!twr_i2c_memory_read_8b(self->_i2c_channel, self->_i2c_address, _TWR_SC16IS740_REG_TXLVL, &value))
93  {
94  return false;
95  }
96 
97  *spaces_available = value;
98 
99  return true;
100 }
101 
102 size_t twr_sc16is740_write(twr_sc16is740_t *self, uint8_t *buffer, size_t length)
103 {
104  size_t spaces_available;
105 
106  if (length > _TWR_SC16IS740_FIFO_SIZE)
107  {
108  return 0;
109  }
110 
111  if (!twr_sc16is740_get_spaces_available(self, &spaces_available))
112  {
113  return 0;
114  }
115 
116  if (spaces_available < length)
117  {
118  return 0;
119  }
120 
121  twr_i2c_memory_transfer_t transfer;
122 
123  transfer.device_address = self->_i2c_address;
124  transfer.memory_address = _TWR_SC16IS740_REG_THR;
125  transfer.length = length;
126  transfer.buffer = buffer;
127 
128  if (!twr_i2c_memory_write(self->_i2c_channel, &transfer))
129  {
130  return 0;
131  }
132 
133  return length;
134 }
135 
136 bool twr_sc16is740_available(twr_sc16is740_t *self, size_t *available)
137 {
138  uint8_t value;
139 
140  if (!twr_i2c_memory_read_8b(self->_i2c_channel, self->_i2c_address, _TWR_SC16IS740_REG_RXLVL, &value))
141  {
142  return false;
143  }
144 
145  *available = value;
146 
147  return true;
148 }
149 
150 size_t twr_sc16is740_read(twr_sc16is740_t *self, uint8_t *buffer, size_t length, twr_tick_t timeout)
151 {
152  size_t read_length = 0;
153 
154  twr_tick_t stop = (timeout != TWR_TICK_INFINITY) ? twr_tick_get() + timeout : TWR_TICK_INFINITY;
155 
156  do
157  {
158  size_t available;
159 
160  if (!twr_sc16is740_available(self, &available))
161  {
162  return 0;
163  }
164 
165  if (available != 0)
166  {
167  twr_i2c_memory_transfer_t transfer;
168 
169  transfer.device_address = self->_i2c_address;
170  transfer.memory_address = _TWR_SC16IS740_REG_RHR;
171  transfer.buffer = buffer + read_length;
172  transfer.length = length - read_length;
173 
174  if (transfer.length > available)
175  {
176  transfer.length = available;
177  }
178 
179  if (transfer.length < 1)
180  {
181  return 0;
182  }
183 
184  if (!twr_i2c_memory_read(self->_i2c_channel, &transfer))
185  {
186  return 0;
187  }
188 
189  read_length += transfer.length;
190 
191  if (read_length == length)
192  {
193  return read_length;
194  }
195  }
196 
197  } while (twr_tick_get() > stop);
198 
199  return read_length;
200 }
201 
202 bool twr_sc16is740_set_baudrate(twr_sc16is740_t *self, twr_sc16is740_baudrate_t baudrate)
203 {
204  uint8_t lcr_read;
205 
206  // Copy LCR
207  if (!twr_i2c_memory_read_8b(self->_i2c_channel, self->_i2c_address, _TWR_SC16IS740_REG_LCR, &lcr_read))
208  {
209  return false;
210  }
211 
212  // Enable access to special registers
213  if (!twr_i2c_memory_write_8b(self->_i2c_channel, self->_i2c_address, _TWR_SC16IS740_REG_LCR, _TWR_SC16IS740_LCR_SPECIAL_REGISTER))
214  {
215  return false;
216  }
217 
218  if (!twr_i2c_memory_write_8b(self->_i2c_channel, self->_i2c_address, _TWR_SC16IS740_SPECIAL_REG_DLL, baudrate))
219  {
220  return false;
221  }
222 
223  if (!twr_i2c_memory_write_8b(self->_i2c_channel, self->_i2c_address, _TWR_SC16IS740_SPECIAL_REG_DLH, 0x00))
224  {
225  return false;
226  }
227 
228  // Restore LCR
229  if (!twr_i2c_memory_write_8b(self->_i2c_channel, self->_i2c_address, _TWR_SC16IS740_REG_LCR, lcr_read))
230  {
231  return false;
232  }
233 
234  return true;
235 }
void twr_i2c_init(twr_i2c_channel_t channel, twr_i2c_speed_t speed)
Initialize I2C channel.
Definition: twr_i2c.c:57
bool twr_i2c_memory_write(twr_i2c_channel_t channel, const twr_i2c_memory_transfer_t *transfer)
Memory write to I2C channel.
Definition: twr_i2c.c:333
bool twr_i2c_memory_read(twr_i2c_channel_t channel, const twr_i2c_memory_transfer_t *transfer)
Memory read from I2C channel.
Definition: twr_i2c.c:371
bool twr_i2c_memory_write_8b(twr_i2c_channel_t channel, uint8_t device_address, uint32_t memory_address, uint8_t data)
Memory write 1 byte to I2C channel.
Definition: twr_i2c.c:408
bool twr_i2c_memory_read_8b(twr_i2c_channel_t channel, uint8_t device_address, uint32_t memory_address, uint8_t *data)
Memory read 1 byte from I2C channel.
Definition: twr_i2c.c:437
twr_i2c_channel_t
I2C channels.
Definition: twr_i2c.h:16
@ TWR_I2C_SPEED_400_KHZ
I2C communication speed is 400 kHz.
Definition: twr_i2c.h:36
bool twr_sc16is740_reset_fifo(twr_sc16is740_t *self, twr_sc16is740_fifo_t fifo)
Reset FIFO.
Definition: twr_sc16is740.c:79
twr_sc16is740_baudrate_t
Baudrates.
Definition: twr_sc16is740.h:23
size_t twr_sc16is740_write(twr_sc16is740_t *self, uint8_t *buffer, size_t length)
Write.
size_t twr_sc16is740_read(twr_sc16is740_t *self, uint8_t *buffer, size_t length, twr_tick_t timeout)
Read.
bool twr_sc16is740_set_baudrate(twr_sc16is740_t *self, twr_sc16is740_baudrate_t baudrate)
Set baudrate.
bool twr_sc16is740_init(twr_sc16is740_t *self, twr_i2c_channel_t i2c_channel, uint8_t i2c_address)
SC16IS740 instance.
Definition: twr_sc16is740.c:23
twr_sc16is740_fifo_t
Fifo type.
Definition: twr_sc16is740.h:14
bool twr_sc16is740_available(twr_sc16is740_t *self, size_t *available)
Get RX FIXO available data.
bool twr_sc16is740_get_spaces_available(twr_sc16is740_t *self, size_t *spaces_available)
Get TX FIXO space available.
Definition: twr_sc16is740.c:88
#define TWR_TICK_INFINITY
Maximum timestamp value.
Definition: twr_tick.h:12
twr_tick_t twr_tick_get(void)
Get absolute timestamp since start of program.
Definition: twr_tick.c:7
uint64_t twr_tick_t
Timestamp data type.
Definition: twr_tick.h:16
I2C memory transfer parameters.
Definition: twr_i2c.h:58
uint32_t memory_address
8-bit I2C memory address (it can be extended to 16-bit format if OR-ed with TWR_I2C_MEMORY_ADDRESS_16...
Definition: twr_i2c.h:63
uint8_t device_address
7-bit I2C device address
Definition: twr_i2c.h:60
size_t length
Length of buffer which is being written or read.
Definition: twr_i2c.h:69
void * buffer
Pointer to buffer which is being written or read.
Definition: twr_i2c.h:66