1 /*
2 * Copyright (c) 2022 HPMicro
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8 #include "hpm_lin_drv.h"
9
10 #define HPM_LIN_DRV_RETRY_COUNT (50000U)
11
lin_master_configure_timing(LIN_Type * ptr,lin_timing_t * timing)12 hpm_stat_t lin_master_configure_timing(LIN_Type *ptr, lin_timing_t *timing)
13 {
14 assert(timing->src_freq_in_hz >= 8000000U);
15 assert((timing->baudrate >= 1000U) && (timing->baudrate <= 20000U));
16
17 uint8_t prescaler, bt_mul;
18 uint16_t bt_div;
19
20 /** set master mode */
21 ptr->TV |= LIN_TV_MASTER_MODE_MASK;
22 ptr->TV |= LIN_TV_INITIAL_MODE_MASK;
23 ptr->TV &= ~LIN_TV_INITIAL_MODE_MASK;
24
25 bt_mul = 20000U / timing->baudrate - 1U;
26 prescaler = log((timing->src_freq_in_hz / ((bt_mul + 1U) * timing->baudrate * 200U))) / log(2U) - 1U;
27 bt_div = timing->src_freq_in_hz / ((1U << (prescaler + 1U)) * (bt_mul + 1U) * timing->baudrate);
28
29 if ((bt_div < 200) || (bt_div > 512)) {
30 return status_invalid_argument;
31 }
32
33 /** src =20MHz baudrate = 19.2KHz */
34 /** bt_div = 260, scaler = 1, bt_mul = 0 */
35 ptr->BAUDRATE_CTL_LOW = bt_div & 0xFF;
36 ptr->BARDRATE_CTL_HIGH = LIN_BARDRATE_CTL_HIGH_BT_DIV_HIGH_SET(bt_div >> 8U)
37 | LIN_BARDRATE_CTL_HIGH_BT_MUL_SET(bt_mul)
38 | LIN_BARDRATE_CTL_HIGH_PRESCL_SET(prescaler);
39
40 return status_success;
41 }
42
lin_slave_configure_timing(LIN_Type * ptr,uint32_t src_freq_in_hz)43 hpm_stat_t lin_slave_configure_timing(LIN_Type *ptr, uint32_t src_freq_in_hz)
44 {
45 assert(src_freq_in_hz >= 8000000U);
46
47 uint8_t prescaler;
48 uint16_t bt_div;
49
50 /** set slave mode */
51 ptr->TV &= ~LIN_TV_MASTER_MODE_MASK;
52 ptr->TV |= LIN_TV_INITIAL_MODE_MASK;
53 ptr->TV &= ~LIN_TV_INITIAL_MODE_MASK;
54
55 prescaler = log((src_freq_in_hz / (20000U * 200U))) / log(2U) - 1U;
56 bt_div = src_freq_in_hz / ((1U << (prescaler + 1U)) * 20000U);
57
58 if ((bt_div < 200) || (bt_div > 512)) {
59 return status_invalid_argument;
60 }
61
62 /** src = 20MHz, prescaler = 1, bt_div = 250 */
63 ptr->BAUDRATE_CTL_LOW = bt_div & 0xFF;
64 ptr->BARDRATE_CTL_HIGH = LIN_BARDRATE_CTL_HIGH_BT_DIV_HIGH_SET(bt_div >> 8U)
65 | LIN_BARDRATE_CTL_HIGH_PRESCL_SET(prescaler);
66
67 return status_success;
68 }
69
lin_get_data_length_from_id(uint8_t id)70 uint8_t lin_get_data_length_from_id(uint8_t id)
71 {
72 switch (LIN_ID_DATA_LEN_GET(id)) {
73 case id_data_length_2bytes:
74 return 2;
75 case id_data_length_2bytes_2:
76 return 2;
77 case id_data_length_4bytes:
78 return 4;
79 case id_data_length_8bytes:
80 return 8;
81 default:
82 return 8;
83 }
84 }
85
lin_get_data_length(LIN_Type * ptr)86 uint8_t lin_get_data_length(LIN_Type *ptr)
87 {
88 uint8_t data_length = 0;
89 if (((ptr->DATA_LEN) & LIN_DATA_LEN_DATA_LENGTH_MASK) == LIN_DATA_LEN_DATA_LENGTH_MASK) {
90 data_length = lin_get_data_length_from_id(ptr->ID);
91 } else {
92 data_length = LIN_DATA_LEN_DATA_LENGTH_GET(ptr->DATA_LEN);
93 }
94 return data_length;
95 }
96
lin_master_transfer(LIN_Type * ptr,lin_trans_config_t * config)97 void lin_master_transfer(LIN_Type *ptr, lin_trans_config_t *config)
98 {
99 uint8_t data_length;
100
101 ptr->ID = config->id;
102
103 if (config->data_length_from_id) {
104 data_length = lin_get_data_length_from_id(ptr->ID);
105 ptr->DATA_LEN = LIN_DATA_LEN_ENH_CHECK_SET(config->enhanced_checksum) | LIN_DATA_LEN_DATA_LENGTH_MASK;
106 } else {
107 data_length = config->data_length;
108 ptr->DATA_LEN = LIN_DATA_LEN_ENH_CHECK_SET(config->enhanced_checksum) | LIN_DATA_LEN_DATA_LENGTH_SET(data_length);
109 }
110
111 /** sent or receive */
112 ptr->CONTROL = 0U;
113 if (config->transmit) {
114 ptr->CONTROL = LIN_CONTROL_TRANSMIT_MASK;
115 }
116
117 if (config->transmit) {
118 for (uint8_t i = 0; i < data_length; i++) {
119 ptr->DATABYTE[i] = *((config->data_buff)++);
120 }
121 }
122
123 /** start */
124 ptr->CONTROL |= LIN_CONTROL_START_REQ_MASK;
125 }
126
lin_master_sent(LIN_Type * ptr,lin_trans_config_t * config)127 hpm_stat_t lin_master_sent(LIN_Type *ptr, lin_trans_config_t *config)
128 {
129 uint32_t retry = 0;
130 uint8_t data_length = 0;
131
132 /** lin active */
133 while (((ptr->STATE & LIN_STATE_LIN_ACTIVE_MASK) == LIN_STATE_LIN_ACTIVE_MASK)) {
134 if (retry > HPM_LIN_DRV_RETRY_COUNT) {
135 break;
136 }
137 retry++;
138 }
139
140 if (retry > HPM_LIN_DRV_RETRY_COUNT) {
141 return status_timeout;
142 }
143
144 ptr->ID = config->id;
145
146 if (config->data_length_from_id) {
147 data_length = lin_get_data_length_from_id(ptr->ID);
148 ptr->DATA_LEN = LIN_DATA_LEN_ENH_CHECK_SET(config->enhanced_checksum) | LIN_DATA_LEN_DATA_LENGTH_MASK;
149 } else {
150 data_length = config->data_length;
151 ptr->DATA_LEN = LIN_DATA_LEN_ENH_CHECK_SET(config->enhanced_checksum) | LIN_DATA_LEN_DATA_LENGTH_SET(data_length);
152 }
153
154 ptr->CONTROL = LIN_CONTROL_TRANSMIT_MASK;
155
156 /** load data into registers */
157 for (uint8_t i = 0; i < data_length; i++) {
158 ptr->DATABYTE[i] = *((config->data_buff)++);
159 }
160
161 /** start */
162 ptr->CONTROL |= LIN_CONTROL_START_REQ_MASK;
163
164 /** lin complete */
165 retry = 0;
166 while (!((ptr->STATE & LIN_STATE_COMPLETE_MASK) == LIN_STATE_COMPLETE_MASK)) {
167 if (retry > HPM_LIN_DRV_RETRY_COUNT * 8) {
168 break;
169 }
170 retry++;
171 }
172
173 if (retry > HPM_LIN_DRV_RETRY_COUNT * 8) {
174 return status_timeout;
175 }
176 return status_success;
177 }
178
lin_master_receive(LIN_Type * ptr,lin_trans_config_t * config)179 hpm_stat_t lin_master_receive(LIN_Type *ptr, lin_trans_config_t *config)
180 {
181 uint32_t retry = 0;
182 uint8_t data_length;
183
184 /** lin active */
185 while (((ptr->STATE & LIN_STATE_LIN_ACTIVE_MASK) == LIN_STATE_LIN_ACTIVE_MASK)) {
186 if (retry > HPM_LIN_DRV_RETRY_COUNT) {
187 break;
188 }
189 retry++;
190 }
191
192 if (retry > HPM_LIN_DRV_RETRY_COUNT) {
193 return status_timeout;
194 }
195
196 ptr->ID = config->id;
197
198 if (config->data_length_from_id) {
199 data_length = lin_get_data_length_from_id(ptr->ID);
200 ptr->DATA_LEN = LIN_DATA_LEN_ENH_CHECK_SET(config->enhanced_checksum) | LIN_DATA_LEN_DATA_LENGTH_MASK;
201 } else {
202 data_length = config->data_length;
203 ptr->DATA_LEN = LIN_DATA_LEN_ENH_CHECK_SET(config->enhanced_checksum) | LIN_DATA_LEN_DATA_LENGTH_SET(data_length);
204 }
205
206 /** receive */
207 ptr->CONTROL = 0U;
208 /** start */
209 ptr->CONTROL |= LIN_CONTROL_START_REQ_MASK;
210
211 /** waiting for receive complete */
212 retry = 0;
213 while (!((ptr->STATE & LIN_STATE_COMPLETE_MASK) == LIN_STATE_COMPLETE_MASK)) {
214 if (retry > HPM_LIN_DRV_RETRY_COUNT * 8) {
215 break;
216 }
217 retry++;
218 }
219
220 if (retry > HPM_LIN_DRV_RETRY_COUNT * 8) {
221 return status_fail;
222 }
223
224 /** load register data into buffer */
225 for (uint8_t i = 0; i < data_length; i++) {
226 *((config->data_buff)++) = ptr->DATABYTE[i];
227 }
228
229 return status_success;
230 }
231
lin_slave_transfer(LIN_Type * ptr,lin_trans_config_t * config)232 void lin_slave_transfer(LIN_Type *ptr, lin_trans_config_t *config)
233 {
234 uint8_t data_length;
235
236 /** transmit or receive */
237 ptr->CONTROL = LIN_CONTROL_TRANSMIT_SET(config->transmit);
238
239 if (config->data_length_from_id) {
240 data_length = lin_get_data_length_from_id(ptr->ID);
241 ptr->DATA_LEN = LIN_DATA_LEN_ENH_CHECK_SET(config->enhanced_checksum) | LIN_DATA_LEN_DATA_LENGTH_MASK;
242 } else {
243 data_length = config->data_length;
244 ptr->DATA_LEN = LIN_DATA_LEN_ENH_CHECK_SET(config->enhanced_checksum) | LIN_DATA_LEN_DATA_LENGTH_SET(data_length);
245 }
246
247 if (config->transmit) {
248 for (uint8_t i = 0; i < data_length; i++) {
249 ptr->DATABYTE[i] = *((config->data_buff)++);
250 }
251 }
252
253 /** data ack */
254 ptr->CONTROL |= LIN_CONTROL_DATA_ACK_MASK;
255 }
256
lin_slave_sent(LIN_Type * ptr,lin_trans_config_t * config)257 hpm_stat_t lin_slave_sent(LIN_Type *ptr, lin_trans_config_t *config)
258 {
259 uint32_t retry = 0;
260 uint8_t data_length;
261
262 /** lin data_req */
263 /** lin active? */
264 while (((ptr->STATE & LIN_STATE_DATA_REQ_MASK) == LIN_STATE_DATA_REQ_MASK)) {
265 if (retry > HPM_LIN_DRV_RETRY_COUNT) {
266 break;
267 }
268 retry++;
269 }
270
271 if (retry > HPM_LIN_DRV_RETRY_COUNT) {
272 return status_timeout;
273 }
274
275 /** transmit */
276 ptr->CONTROL = LIN_CONTROL_TRANSMIT_MASK;
277
278 if (config->data_length_from_id) {
279 data_length = lin_get_data_length_from_id(ptr->ID);
280 ptr->DATA_LEN = LIN_DATA_LEN_ENH_CHECK_SET(config->enhanced_checksum) | LIN_DATA_LEN_DATA_LENGTH_MASK;
281 } else {
282 data_length = config->data_length;
283 ptr->DATA_LEN = LIN_DATA_LEN_ENH_CHECK_SET(config->enhanced_checksum) | LIN_DATA_LEN_DATA_LENGTH_SET(data_length);
284 }
285
286 for (uint8_t i = 0; i < data_length; i++) {
287 ptr->DATABYTE[i] = *((config->data_buff)++);
288 }
289
290 /** data ack */
291 ptr->CONTROL |= LIN_CONTROL_DATA_ACK_MASK;
292
293 /** lin complete */
294 retry = 0;
295 while (!((ptr->STATE & LIN_STATE_COMPLETE_MASK) == LIN_STATE_COMPLETE_MASK)) {
296 if (retry > HPM_LIN_DRV_RETRY_COUNT * 8) {
297 break;
298 }
299 retry++;
300 }
301
302 if (retry > HPM_LIN_DRV_RETRY_COUNT * 8) {
303 return status_timeout;
304 }
305 return status_success;
306 }
307
lin_slave_receive(LIN_Type * ptr,lin_trans_config_t * config)308 hpm_stat_t lin_slave_receive(LIN_Type *ptr, lin_trans_config_t *config)
309 {
310 uint32_t retry = 0;
311 uint8_t data_length;
312
313 /** lin data_req */
314 while (((ptr->STATE & LIN_STATE_DATA_REQ_MASK) == LIN_STATE_DATA_REQ_MASK)) {
315 if (retry > HPM_LIN_DRV_RETRY_COUNT) {
316 break;
317 }
318 retry++;
319 }
320
321 if (retry > HPM_LIN_DRV_RETRY_COUNT) {
322 return status_timeout;
323 }
324
325 /** receive */
326 ptr->CONTROL = 0U;
327
328 if (config->data_length_from_id) {
329 data_length = lin_get_data_length_from_id(ptr->ID);
330 ptr->DATA_LEN = LIN_DATA_LEN_ENH_CHECK_SET(config->enhanced_checksum) | LIN_DATA_LEN_DATA_LENGTH_MASK;
331 } else {
332 data_length = config->data_length;
333 ptr->DATA_LEN = LIN_DATA_LEN_ENH_CHECK_SET(config->enhanced_checksum) | LIN_DATA_LEN_DATA_LENGTH_SET(data_length);
334 }
335
336 /** data ack */
337 ptr->CONTROL |= LIN_CONTROL_DATA_ACK_MASK;
338
339 /** lin complete */
340 retry = 0;
341 while (!((ptr->STATE & LIN_STATE_COMPLETE_MASK) == LIN_STATE_COMPLETE_MASK)) {
342 if (retry > HPM_LIN_DRV_RETRY_COUNT * 8) {
343 break;
344 }
345 retry++;
346 }
347
348 if (retry > HPM_LIN_DRV_RETRY_COUNT * 8) {
349 return status_timeout;
350 }
351
352 for (uint8_t i = 0; i < data_length; i++) {
353 *((config->data_buff)++) = ptr->DATABYTE[i];
354 }
355
356 return status_success;
357 }
358