• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 HPMicro
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include "hpm_linv2_drv.h"
9 
10 #define HPM_LIN_DRV_RETRY_COUNT (50000U)
11 
lin_master_configure_timing(LINV2_Type * ptr,lin_timing_t * timing)12 hpm_stat_t lin_master_configure_timing(LINV2_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->TIMING_CONTROL = LINV2_TIMING_CONTROL_MASTER_MODE_MASK;
22     ptr->TIMING_CONTROL |= LINV2_TIMING_CONTROL_LIN_INITIAL_MASK;
23     ptr->TIMING_CONTROL &= ~LINV2_TIMING_CONTROL_LIN_INITIAL_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->TIMING_CONTROL |= LINV2_TIMING_CONTROL_BT_DIV_SET(bt_div)
36                         | LINV2_TIMING_CONTROL_BT_MUL_SET(bt_mul)
37                         | LINV2_TIMING_CONTROL_PRESCL_SET(prescaler);
38 
39     return status_success;
40 }
41 
lin_slave_configure_timing(LINV2_Type * ptr,uint32_t src_freq_in_hz)42 hpm_stat_t lin_slave_configure_timing(LINV2_Type *ptr, uint32_t src_freq_in_hz)
43 {
44     assert(src_freq_in_hz >= 8000000U);
45 
46     uint8_t prescaler;
47     uint16_t bt_div;
48 
49     /** set slave mode, clean bt_div, bit_mul, prescl */
50     ptr->TIMING_CONTROL = 0;
51     ptr->TIMING_CONTROL |= LINV2_TIMING_CONTROL_LIN_INITIAL_MASK;
52     ptr->TIMING_CONTROL &= ~LINV2_TIMING_CONTROL_LIN_INITIAL_MASK;
53 
54     prescaler = log((src_freq_in_hz / (20000U * 200U))) / log(2U) - 1U;
55     bt_div = src_freq_in_hz / ((1U << (prescaler + 1U)) * 20000U);
56 
57     if ((bt_div < 200) || (bt_div >= 512)) {
58         return status_invalid_argument;
59     }
60 
61     /** src = 20MHz, prescaler = 1, bt_div = 250 */
62     /* TODO: set wakeup_len */
63     ptr->TIMING_CONTROL = LINV2_TIMING_CONTROL_BT_DIV_SET(bt_div)
64                         | LINV2_TIMING_CONTROL_PRESCL_SET(prescaler);
65 
66     /* disable break_err detect */
67     ptr->CONTROL_STATUS = LINV2_CONTROL_STATUS_BREAK_ERR_DIS_MASK;
68 
69     return status_success;
70 }
71 
lin_get_data_length_from_id(uint8_t id)72 uint8_t lin_get_data_length_from_id(uint8_t id)
73 {
74     switch (LIN_ID_DATA_LEN_GET(id)) {
75     case id_data_length_2bytes:
76         return 2;
77     case id_data_length_2bytes_2:
78         return 2;
79     case id_data_length_4bytes:
80         return 4;
81     case id_data_length_8bytes:
82         return 8;
83     default:
84         return 8;
85     }
86 }
87 
lin_get_data_length(LINV2_Type * ptr)88 uint8_t lin_get_data_length(LINV2_Type *ptr)
89 {
90     uint8_t data_length = 0;
91     if (((ptr->DATA_LEN_ID) & LINV2_DATA_LEN_ID_DATA_LEN_MASK) == LINV2_DATA_LEN_ID_DATA_LEN_MASK) {
92         data_length = lin_get_data_length_from_id(lin_get_id(ptr));
93     } else {
94         data_length = LINV2_DATA_LEN_ID_DATA_LEN_GET(ptr->DATA_LEN_ID);
95     }
96     return data_length;
97 }
98 
lin_master_transfer(LINV2_Type * ptr,lin_trans_config_t * config)99 void lin_master_transfer(LINV2_Type *ptr, lin_trans_config_t *config)
100 {
101     uint8_t data_length;
102 
103     /** config id */
104     if (config->data_length_from_id) {
105         data_length = lin_get_data_length_from_id(lin_get_id(ptr));
106         ptr->DATA_LEN_ID = LINV2_DATA_LEN_ID_ENH_CHECK_SET(config->enhanced_checksum) | LINV2_DATA_LEN_ID_DATA_LEN_MASK | LINV2_DATA_LEN_ID_ID_SET(config->id);
107     } else {
108         data_length = config->data_length;
109         ptr->DATA_LEN_ID = LINV2_DATA_LEN_ID_ENH_CHECK_SET(config->enhanced_checksum) | LINV2_DATA_LEN_ID_DATA_LEN_SET(data_length) | LINV2_DATA_LEN_ID_ID_SET(config->id);
110     }
111 
112     /** sent or receive */
113     ptr->CONTROL_STATUS = 0U;
114     if (config->transmit) {
115         ptr->CONTROL_STATUS |= LINV2_CONTROL_STATUS_TRANSMIT_MASK;
116     }
117 
118     if (config->transmit) {
119         for (uint8_t i = 0; i < data_length; i++) {
120             ptr->DATA_BYTE[i] = *((config->data_buff)++);
121         }
122     }
123 
124     /** start */
125     ptr->CONTROL_STATUS |= LINV2_CONTROL_STATUS_START_REQ_MASK;
126 }
127 
lin_master_sent(LINV2_Type * ptr,lin_trans_config_t * config)128 hpm_stat_t lin_master_sent(LINV2_Type *ptr, lin_trans_config_t *config)
129 {
130     uint32_t retry = 0;
131     uint8_t data_length = 0;
132 
133     /** wait for lin inactive */
134     while (lin_is_active(ptr)) {
135         if (retry > HPM_LIN_DRV_RETRY_COUNT) {
136             break;
137         }
138         retry++;
139     }
140 
141     if (retry > HPM_LIN_DRV_RETRY_COUNT) {
142         return status_timeout;
143     }
144 
145     /** config id */
146     if (config->data_length_from_id) {
147         data_length = lin_get_data_length_from_id(lin_get_id(ptr));
148         ptr->DATA_LEN_ID = LINV2_DATA_LEN_ID_ENH_CHECK_SET(config->enhanced_checksum) | LINV2_DATA_LEN_ID_DATA_LEN_MASK | LINV2_DATA_LEN_ID_ID_SET(config->id);
149     } else {
150         data_length = config->data_length;
151         ptr->DATA_LEN_ID = LINV2_DATA_LEN_ID_ENH_CHECK_SET(config->enhanced_checksum) | LINV2_DATA_LEN_ID_DATA_LEN_SET(data_length) | LINV2_DATA_LEN_ID_ID_SET(config->id);
152     }
153 
154     ptr->CONTROL_STATUS = LINV2_CONTROL_STATUS_TRANSMIT_MASK;
155 
156     /** load data into registers */
157     for (uint8_t i = 0; i < data_length; i++) {
158         ptr->DATA_BYTE[i] = *((config->data_buff)++);
159     }
160 
161     /** start */
162     ptr->CONTROL_STATUS |=  LINV2_CONTROL_STATUS_START_REQ_MASK;
163 
164     /** waiting for lin complete */
165     retry = 0;
166     while (!lin_is_complete(ptr)) {
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(LINV2_Type * ptr,lin_trans_config_t * config)179 hpm_stat_t lin_master_receive(LINV2_Type *ptr, lin_trans_config_t *config)
180 {
181     uint32_t retry = 0;
182     uint8_t data_length;
183 
184     /** waiting for lin inactive */
185     while (lin_is_active(ptr)) {
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     /** config id */
197     if (config->data_length_from_id) {
198         data_length = lin_get_data_length_from_id(lin_get_id(ptr));
199         ptr->DATA_LEN_ID = LINV2_DATA_LEN_ID_ENH_CHECK_SET(config->enhanced_checksum) | LINV2_DATA_LEN_ID_DATA_LEN_MASK | LINV2_DATA_LEN_ID_ID_SET(config->id);
200     } else {
201         data_length = config->data_length;
202         ptr->DATA_LEN_ID = LINV2_DATA_LEN_ID_ENH_CHECK_SET(config->enhanced_checksum) | LINV2_DATA_LEN_ID_DATA_LEN_SET(data_length) | LINV2_DATA_LEN_ID_ID_SET(config->id);
203     }
204 
205     /** receive */
206     ptr->CONTROL_STATUS = 0U;
207     /** start */
208     ptr->CONTROL_STATUS |= LINV2_CONTROL_STATUS_START_REQ_MASK;
209 
210     /** waiting for receive complete */
211     retry = 0;
212     while (!lin_is_complete(ptr)) {
213         if (retry > HPM_LIN_DRV_RETRY_COUNT * 8) {
214             break;
215         }
216         retry++;
217     }
218 
219     if (retry > HPM_LIN_DRV_RETRY_COUNT * 8) {
220         return status_fail;
221     }
222 
223     /** load register data into buffer */
224     for (uint8_t i = 0; i < data_length; i++) {
225         *((config->data_buff)++) = ptr->DATA_BYTE[i];
226     }
227 
228     return status_success;
229 }
230 
lin_slave_transfer(LINV2_Type * ptr,lin_trans_config_t * config)231 void lin_slave_transfer(LINV2_Type *ptr, lin_trans_config_t *config)
232 {
233     uint8_t data_length;
234 
235     /** transmit or receive */
236     ptr->CONTROL_STATUS &= ~LINV2_CONTROL_STATUS_TRANSMIT_MASK;
237     if (config->transmit) {
238         ptr->CONTROL_STATUS |= LINV2_CONTROL_STATUS_TRANSMIT_MASK;
239     }
240 
241     /* clean enh_check and data_len */
242     ptr->DATA_LEN_ID &= ~(LINV2_DATA_LEN_ID_ENH_CHECK_MASK | LINV2_DATA_LEN_ID_DATA_LEN_MASK);
243     if (config->data_length_from_id) {
244         data_length = lin_get_data_length_from_id(lin_get_id(ptr));
245         ptr->DATA_LEN_ID |= LINV2_DATA_LEN_ID_ENH_CHECK_SET(config->enhanced_checksum) | LINV2_DATA_LEN_ID_DATA_LEN_MASK;
246     } else {
247         data_length = config->data_length;
248         ptr->DATA_LEN_ID |= LINV2_DATA_LEN_ID_ENH_CHECK_SET(config->enhanced_checksum) | LINV2_DATA_LEN_ID_DATA_LEN_SET(data_length);
249     }
250 
251     if (config->transmit) {
252         for (uint8_t i = 0; i < data_length; i++) {
253             ptr->DATA_BYTE[i] = *((config->data_buff)++);
254         }
255     }
256 
257     /** data ack */
258     ptr->CONTROL_STATUS |= LINV2_CONTROL_STATUS_DATA_ACK_MASK;
259 }
260 
lin_slave_sent(LINV2_Type * ptr,lin_trans_config_t * config)261 hpm_stat_t lin_slave_sent(LINV2_Type *ptr, lin_trans_config_t *config)
262 {
263     uint32_t retry = 0;
264     uint8_t data_length;
265 
266     /** waiting for lin data_req */
267     while (!((ptr->CONTROL_STATUS & LINV2_CONTROL_STATUS_DATA_REQ_MASK) == LINV2_CONTROL_STATUS_DATA_REQ_MASK)) {
268         if (retry > HPM_LIN_DRV_RETRY_COUNT) {
269             break;
270         }
271         retry++;
272     }
273 
274     if (retry > HPM_LIN_DRV_RETRY_COUNT) {
275         return status_timeout;
276     }
277 
278     /** transmit */
279     ptr->CONTROL_STATUS = LINV2_CONTROL_STATUS_TRANSMIT_MASK;
280 
281     /* clean enh_check and data_len */
282     ptr->DATA_LEN_ID &= ~(LINV2_DATA_LEN_ID_ENH_CHECK_MASK | LINV2_DATA_LEN_ID_DATA_LEN_MASK);
283     if (config->data_length_from_id) {
284         data_length = lin_get_data_length_from_id(lin_get_id(ptr));
285         ptr->DATA_LEN_ID |= LINV2_DATA_LEN_ID_ENH_CHECK_SET(config->enhanced_checksum) | LINV2_DATA_LEN_ID_DATA_LEN_MASK;
286     } else {
287         data_length = config->data_length;
288         ptr->DATA_LEN_ID |= LINV2_DATA_LEN_ID_ENH_CHECK_SET(config->enhanced_checksum) | LINV2_DATA_LEN_ID_DATA_LEN_SET(data_length);
289     }
290 
291     for (uint8_t i = 0; i < data_length; i++) {
292         ptr->DATA_BYTE[i] = *((config->data_buff)++);
293     }
294 
295     /** data ack */
296     ptr->CONTROL_STATUS |= LINV2_CONTROL_STATUS_DATA_ACK_MASK;
297 
298     /** waiting for lin complete */
299     retry = 0;
300     while (!lin_is_complete(ptr)) {
301         if (retry > HPM_LIN_DRV_RETRY_COUNT * 8) {
302             break;
303         }
304         retry++;
305     }
306 
307     if (retry > HPM_LIN_DRV_RETRY_COUNT * 8) {
308         return status_timeout;
309     }
310     return status_success;
311 }
312 
lin_slave_receive(LINV2_Type * ptr,lin_trans_config_t * config)313 hpm_stat_t lin_slave_receive(LINV2_Type *ptr, lin_trans_config_t *config)
314 {
315     uint32_t retry = 0;
316     uint8_t data_length;
317 
318     /** waiting for lin data_req */
319     while (!((ptr->CONTROL_STATUS & LINV2_CONTROL_STATUS_DATA_REQ_MASK) == LINV2_CONTROL_STATUS_DATA_REQ_MASK)) {
320         if (retry > HPM_LIN_DRV_RETRY_COUNT) {
321             break;
322         }
323         retry++;
324     }
325 
326     if (retry > HPM_LIN_DRV_RETRY_COUNT) {
327         return status_timeout;
328     }
329 
330     /** receive */
331     ptr->CONTROL_STATUS = 0U;
332 
333     /* clean enh_check and data_len */
334     ptr->DATA_LEN_ID &= ~(LINV2_DATA_LEN_ID_ENH_CHECK_MASK | LINV2_DATA_LEN_ID_DATA_LEN_MASK);
335     if (config->data_length_from_id) {
336         data_length = lin_get_data_length_from_id(lin_get_id(ptr));
337         ptr->DATA_LEN_ID |= LINV2_DATA_LEN_ID_ENH_CHECK_SET(config->enhanced_checksum) | LINV2_DATA_LEN_ID_DATA_LEN_MASK;
338     } else {
339         data_length = config->data_length;
340         ptr->DATA_LEN_ID |= LINV2_DATA_LEN_ID_ENH_CHECK_SET(config->enhanced_checksum) | LINV2_DATA_LEN_ID_DATA_LEN_SET(data_length);
341     }
342 
343     /** data ack */
344     ptr->CONTROL_STATUS |= LINV2_CONTROL_STATUS_DATA_ACK_MASK;
345 
346     /** waiting for lin complete */
347     retry = 0;
348     while (!lin_is_complete(ptr)) {
349         if (retry > HPM_LIN_DRV_RETRY_COUNT * 8) {
350             break;
351         }
352         retry++;
353     }
354 
355     if (retry > HPM_LIN_DRV_RETRY_COUNT * 8) {
356         return status_timeout;
357     }
358 
359     for (uint8_t i = 0; i < data_length; i++) {
360         *((config->data_buff)++) = ptr->DATA_BYTE[i];
361     }
362 
363     return status_success;
364 }
365 
lin_slave_dma_transfer(LINV2_Type * ptr,lin_trans_config_t * config)366 void lin_slave_dma_transfer(LINV2_Type *ptr, lin_trans_config_t *config)
367 {
368     ptr->DMA_CONTROL = LINV2_DMA_CONTROL_DMA_REQ_ENABLE_MASK
369                     | LINV2_DMA_CONTROL_DMA_REQ_ID_SET(config->id)
370                     | LINV2_DMA_CONTROL_DMA_REQ_ID_TYPE_SET(config->transmit)
371                     | LINV2_DMA_CONTROL_DMA_REQ_LEN_SET(config->data_length)
372                     | LINV2_DMA_CONTROL_DMA_REQ_ENH_CHK_SET(config->enhanced_checksum);
373 }