SAM4SD32 (SAM4S-EK2)
Loading...
Searching...
No Matches
twi.c
Go to the documentation of this file.
1
33/*
34 * Support and FAQ: visit <a href="https://www.microchip.com/support/">Microchip Support</a>
35 */
36
37#include "twi.h"
38
40
41#ifdef __cplusplus
42extern "C" {
43#endif
46
69
70/* Low level time limit of I2C Fast Mode. */
71#define LOW_LEVEL_TIME_LIMIT 384000
72#define I2C_FAST_MODE_SPEED 400000
73#define TWI_CLK_DIVIDER 2
74#if SAMG55
75#define TWI_CLK_CALC_ARGU 3
76#else
77#define TWI_CLK_CALC_ARGU 4
78#endif
79#define TWI_CLK_DIV_MAX 0xFF
80#define TWI_CLK_DIV_MIN 7
81
82#define TWI_WP_KEY_VALUE TWI_WPMR_WPKEY_PASSWD
83
90{
91 /* Set Master Disable bit and Slave Disable bit */
92 p_twi->TWI_CR = TWI_CR_MSDIS;
93 p_twi->TWI_CR = TWI_CR_SVDIS;
94
95 /* Set Master Enable bit */
96 p_twi->TWI_CR = TWI_CR_MSEN;
97}
98
105{
106 /* Set Master Disable bit */
107 p_twi->TWI_CR = TWI_CR_MSDIS;
108}
109
118uint32_t twi_master_init(Twi *p_twi, const twi_options_t *p_opt)
119{
120 uint32_t status = TWI_SUCCESS;
121
122 /* Disable TWI interrupts */
123 p_twi->TWI_IDR = ~0UL;
124
125 /* Dummy read in status register */
126 p_twi->TWI_SR;
127
128 /* Reset TWI peripheral */
129 twi_reset(p_twi);
130
132
133 /* Select the speed */
134 if (twi_set_speed(p_twi, p_opt->speed, p_opt->master_clk) == FAIL) {
135 /* The desired speed setting is rejected */
136 status = TWI_INVALID_ARGUMENT;
137 }
138
139 if (p_opt->smbus == 1) {
140 p_twi->TWI_CR = TWI_CR_QUICK;
141 }
142
143 return status;
144}
145
156uint32_t twi_set_speed(Twi *p_twi, uint32_t ul_speed, uint32_t ul_mck)
157{
158 uint32_t ckdiv = 0;
159 uint32_t c_lh_div;
160 uint32_t cldiv, chdiv;
161
162 if (ul_speed > I2C_FAST_MODE_SPEED) {
163 return FAIL;
164 }
165
166 /* Low level time not less than 1.3us of I2C Fast Mode. */
167 if (ul_speed > LOW_LEVEL_TIME_LIMIT) {
168 /* Low level of time fixed for 1.3us. */
170 chdiv = ul_mck / ((ul_speed + (ul_speed - LOW_LEVEL_TIME_LIMIT)) * TWI_CLK_DIVIDER) - TWI_CLK_CALC_ARGU;
171
172 /* cldiv must fit in 8 bits, ckdiv must fit in 3 bits */
173 while ((cldiv > TWI_CLK_DIV_MAX) && (ckdiv < TWI_CLK_DIV_MIN)) {
174 /* Increase clock divider */
175 ckdiv++;
176 /* Divide cldiv value */
177 cldiv /= TWI_CLK_DIVIDER;
178 }
179 /* chdiv must fit in 8 bits, ckdiv must fit in 3 bits */
180 while ((chdiv > TWI_CLK_DIV_MAX) && (ckdiv < TWI_CLK_DIV_MIN)) {
181 /* Increase clock divider */
182 ckdiv++;
183 /* Divide cldiv value */
184 chdiv /= TWI_CLK_DIVIDER;
185 }
186
187 /* set clock waveform generator register */
188 p_twi->TWI_CWGR =
189 TWI_CWGR_CLDIV(cldiv) | TWI_CWGR_CHDIV(chdiv) |
190 TWI_CWGR_CKDIV(ckdiv);
191 } else {
192 c_lh_div = ul_mck / (ul_speed * TWI_CLK_DIVIDER) - TWI_CLK_CALC_ARGU;
193
194 /* cldiv must fit in 8 bits, ckdiv must fit in 3 bits */
195 while ((c_lh_div > TWI_CLK_DIV_MAX) && (ckdiv < TWI_CLK_DIV_MIN)) {
196 /* Increase clock divider */
197 ckdiv++;
198 /* Divide cldiv value */
199 c_lh_div /= TWI_CLK_DIVIDER;
200 }
201
202 /* set clock waveform generator register */
203 p_twi->TWI_CWGR =
204 TWI_CWGR_CLDIV(c_lh_div) | TWI_CWGR_CHDIV(c_lh_div) |
205 TWI_CWGR_CKDIV(ckdiv);
206 }
207
208 return PASS;
209}
210
219uint32_t twi_probe(Twi *p_twi, uint8_t uc_slave_addr)
220{
221 twi_packet_t packet;
222 uint8_t data = 0;
223
224 /* Data to send */
225 packet.buffer = &data;
226 /* Data length */
227 packet.length = 1;
228 /* Slave chip address */
229 packet.chip = (uint32_t) uc_slave_addr;
230 /* Internal chip address */
231 packet.addr[0] = 0;
232 /* Address length */
233 packet.addr_length = 0;
234
235 /* Perform a master write access */
236 return (twi_master_write(p_twi, &packet));
237}
238
239
249uint32_t twi_mk_addr(const uint8_t *addr, int len)
250{
251 uint32_t val;
252
253 if (len == 0)
254 return 0;
255
256 val = addr[0];
257 if (len > 1) {
258 val <<= 8;
259 val |= addr[1];
260 }
261 if (len > 2) {
262 val <<= 8;
263 val |= addr[2];
264 }
265 return val;
266}
267
278uint32_t twi_master_read(Twi *p_twi, twi_packet_t *p_packet)
279{
280 uint32_t status;
281 uint32_t cnt = p_packet->length;
282 uint8_t *buffer = p_packet->buffer;
283 uint8_t stop_sent = 0;
284 uint32_t timeout = TWI_TIMEOUT;;
285
286 /* Check argument */
287 if (cnt == 0) {
289 }
290
291 /* Set read mode, slave address and 3 internal address byte lengths */
292 p_twi->TWI_MMR = 0;
293 p_twi->TWI_MMR = TWI_MMR_MREAD | TWI_MMR_DADR(p_packet->chip) |
294 ((p_packet->addr_length << TWI_MMR_IADRSZ_Pos) &
296
297 /* Set internal address for remote chip */
298 p_twi->TWI_IADR = 0;
299 p_twi->TWI_IADR = twi_mk_addr(p_packet->addr, p_packet->addr_length);
300
301 /* Send a START condition */
302 if (cnt == 1) {
304 stop_sent = 1;
305 } else {
306 p_twi->TWI_CR = TWI_CR_START;
307 stop_sent = 0;
308 }
309
310 while (cnt > 0) {
311 status = p_twi->TWI_SR;
312 if (status & TWI_SR_NACK) {
313 return TWI_RECEIVE_NACK;
314 }
315
316 if (!timeout--) {
317 return TWI_ERROR_TIMEOUT;
318 }
319
320 /* Last byte ? */
321 if (cnt == 1 && !stop_sent) {
322 p_twi->TWI_CR = TWI_CR_STOP;
323 stop_sent = 1;
324 }
325
326 if (!(status & TWI_SR_RXRDY)) {
327 continue;
328 }
329 *buffer++ = p_twi->TWI_RHR;
330
331 cnt--;
332 timeout = TWI_TIMEOUT;
333 }
334
335 while (!(p_twi->TWI_SR & TWI_SR_TXCOMP)) {
336 }
337
338 p_twi->TWI_SR;
339
340 return TWI_SUCCESS;
341}
342
353uint32_t twi_master_write(Twi *p_twi, twi_packet_t *p_packet)
354{
355 uint32_t status;
356 uint32_t cnt = p_packet->length;
357 uint8_t *buffer = p_packet->buffer;
358
359 /* Check argument */
360 if (cnt == 0) {
362 }
363
364 /* Set write mode, slave address and 3 internal address byte lengths */
365 p_twi->TWI_MMR = 0;
366 p_twi->TWI_MMR = TWI_MMR_DADR(p_packet->chip) |
367 ((p_packet->addr_length << TWI_MMR_IADRSZ_Pos) &
369
370 /* Set internal address for remote chip */
371 p_twi->TWI_IADR = 0;
372 p_twi->TWI_IADR = twi_mk_addr(p_packet->addr, p_packet->addr_length);
373
374 /* Send all bytes */
375 while (cnt > 0) {
376 status = p_twi->TWI_SR;
377 if (status & TWI_SR_NACK) {
378 return TWI_RECEIVE_NACK;
379 }
380
381 if (!(status & TWI_SR_TXRDY)) {
382 continue;
383 }
384 p_twi->TWI_THR = *buffer++;
385
386 cnt--;
387 }
388
389 while (1) {
390 status = p_twi->TWI_SR;
391 if (status & TWI_SR_NACK) {
392 return TWI_RECEIVE_NACK;
393 }
394
395 if (status & TWI_SR_TXRDY) {
396 break;
397 }
398 }
399
400 p_twi->TWI_CR = TWI_CR_STOP;
401
402 while (!(p_twi->TWI_SR & TWI_SR_TXCOMP)) {
403 }
404
405 return TWI_SUCCESS;
406}
407
414void twi_enable_interrupt(Twi *p_twi, uint32_t ul_sources)
415{
416 /* Enable the specified interrupts */
417 p_twi->TWI_IER = ul_sources;
418}
419
426void twi_disable_interrupt(Twi *p_twi, uint32_t ul_sources)
427{
428 /* Disable the specified interrupts */
429 p_twi->TWI_IDR = ul_sources;
430 /* Dummy read */
431 p_twi->TWI_SR;
432}
433
442{
443 return p_twi->TWI_SR;
444}
445
454{
455 return p_twi->TWI_IMR;
456}
457
465uint8_t twi_read_byte(Twi *p_twi)
466{
467 return p_twi->TWI_RHR;
468}
469
476void twi_write_byte(Twi *p_twi, uint8_t uc_byte)
477{
478 p_twi->TWI_THR = uc_byte;
479}
480
487{
488 /* Set Master Disable bit and Slave Disable bit */
489 p_twi->TWI_CR = TWI_CR_MSDIS;
490 p_twi->TWI_CR = TWI_CR_SVDIS;
491
492 /* Set Slave Enable bit */
493 p_twi->TWI_CR = TWI_CR_SVEN;
494}
495
502{
503 /* Set Slave Disable bit */
504 p_twi->TWI_CR = TWI_CR_SVDIS;
505}
506
513void twi_slave_init(Twi *p_twi, uint32_t ul_device_addr)
514{
515 /* Disable TWI interrupts */
516 p_twi->TWI_IDR = ~0UL;
517 p_twi->TWI_SR;
518
519 /* Reset TWI */
520 twi_reset(p_twi);
521
522 /* Set slave address in slave mode */
523 p_twi->TWI_SMR = TWI_SMR_SADR(ul_device_addr);
524
525 /* Enable slave mode */
527}
528
535void twi_set_slave_addr(Twi *p_twi, uint32_t ul_device_addr)
536{
537 /* Set slave address */
538 p_twi->TWI_SMR = TWI_SMR_SADR(ul_device_addr);
539}
540
551uint32_t twi_slave_read(Twi *p_twi, uint8_t *p_data)
552{
553 uint32_t status, cnt = 0;
554
555 do {
556 status = p_twi->TWI_SR;
557 if (status & TWI_SR_SVACC) {
558 if (!(status & TWI_SR_GACC) &&
559 ((status & (TWI_SR_SVREAD | TWI_SR_RXRDY))
560 == (TWI_SR_SVREAD | TWI_SR_RXRDY))) {
561 *p_data++ = (uint8_t) p_twi->TWI_RHR;
562 cnt++;
563 }
564 } else if ((status & (TWI_SR_EOSACC | TWI_SR_TXCOMP))
566 break;
567 }
568 } while (1);
569
570 return cnt;
571}
572
583uint32_t twi_slave_write(Twi *p_twi, uint8_t *p_data)
584{
585 uint32_t status, cnt = 0;
586
587 do {
588 status = p_twi->TWI_SR;
589 if (status & TWI_SR_SVACC) {
590 if (!(status & (TWI_SR_GACC | TWI_SR_SVREAD)) &&
591 (status & TWI_SR_TXRDY)) {
592 p_twi->TWI_THR = *p_data++;
593 cnt++;
594 }
595 } else if ((status & (TWI_SR_EOSACC | TWI_SR_TXCOMP))
597 break;
598 }
599 } while (1);
600
601 return cnt;
602}
603
609void twi_reset(Twi *p_twi)
610{
611 /* Set SWRST bit to reset TWI peripheral */
612 p_twi->TWI_CR = TWI_CR_SWRST;
613 p_twi->TWI_RHR;
614}
615
624{
625 Pdc *p_pdc_base = NULL;
626#if !SAMG
627 if (p_twi == TWI0) {
628 p_pdc_base = PDC_TWI0;
629 } else
630#endif
631#ifdef PDC_TWI1
632 if (p_twi == TWI1) {
633 p_pdc_base = PDC_TWI1;
634 } else
635#endif
636#ifdef PDC_TWI2
637 if (p_twi == TWI2) {
638 p_pdc_base = PDC_TWI2;
639 } else
640#endif
641 {
642 Assert(false);
643 }
644
645 return p_pdc_base;
646}
647
648#if (SAM4E || SAM4C || SAMG || SAM4CP || SAM4CM)
655void twi_set_write_protection(Twi *p_twi, bool flag)
656{
657
658 p_twi->TWI_WPMR = (flag ? TWI_WPMR_WPEN : 0) | TWI_WP_KEY_VALUE;
659}
660
667void twi_read_write_protection_status(Twi *p_twi, uint32_t *p_status)
668{
669
670 *p_status = p_twi->TWI_WPSR;
671}
672#endif
673
674#if SAMG55
681void twi_smbus_set_timing(Twi *p_twi, uint32_t ul_timing)
682{
683 p_twi->TWI_SMBTR = ul_timing;;
684}
685
692void twi_set_alternative_command(Twi *p_twi, uint32_t ul_alt_cmd)
693{
694 p_twi->TWI_ACR = ul_alt_cmd;;
695}
696
703void twi_set_filter(Twi *p_twi, uint32_t ul_filter)
704{
705 p_twi->TWI_FILTR = ul_filter;;
706}
707
715void twi_mask_slave_addr(Twi *p_twi, uint32_t ul_mask)
716{
717 p_twi->TWI_SMR |= TWI_SMR_MASK(ul_mask);
718}
719
733void twi_set_sleepwalking(Twi *p_twi,
734 uint32_t ul_matching_addr1, bool flag1,
735 uint32_t ul_matching_addr2, bool flag2,
736 uint32_t ul_matching_addr3, bool flag3,
737 uint32_t ul_matching_data, bool flag)
738{
739 uint32_t temp = 0;
740
741 if (flag1) {
742 temp |= TWI_SWMR_SADR1(ul_matching_addr1);
743 }
744
745 if (flag2) {
746 temp |= TWI_SWMR_SADR2(ul_matching_addr2);
747 }
748
749 if (flag3) {
750 temp |= TWI_SWMR_SADR3(ul_matching_addr3);
751 }
752
753 if (flag) {
754 temp |= TWI_SWMR_DATAM(ul_matching_data);
755 }
756
757 p_twi->TWI_SWMR = temp;
758}
759#endif
761
763
764#ifdef __cplusplus
765}
766#endif
769
770
#define TWI_MMR_MREAD
(TWI_MMR) Master Read Direction
#define TWI_SR_TXCOMP
(TWI_SR) Transmission Completed (automatically set / reset)
#define TWI_SR_RXRDY
(TWI_SR) Receive Holding Register Ready (automatically set / reset)
#define TWI_CWGR_CHDIV(value)
#define TWI_CR_START
(TWI_CR) Send a START Condition
#define TWI_CR_SWRST
(TWI_CR) Software Reset
#define TWI_SR_GACC
(TWI_SR) General Call Access (clear on read)
#define TWI_SMR_SADR(value)
#define TWI_CR_MSDIS
(TWI_CR) TWI Master Mode Disabled
#define TWI_SR_TXRDY
(TWI_SR) Transmit Holding Register Ready (automatically set / reset)
#define TWI_SR_NACK
(TWI_SR) Not Acknowledged (clear on read)
#define TWI_CR_SVEN
(TWI_CR) TWI Slave Mode Enabled
#define TWI_MMR_IADRSZ_Msk
(TWI_MMR) Internal Device Address Size
#define TWI_SR_EOSACC
(TWI_SR) End Of Slave Access (clear on read)
#define TWI_CWGR_CLDIV(value)
#define TWI_CR_STOP
(TWI_CR) Send a STOP Condition
#define TWI_MMR_IADRSZ_Pos
#define TWI_SR_SVREAD
(TWI_SR) Slave Read (automatically set / reset)
#define TWI_MMR_DADR(value)
#define TWI_CR_QUICK
(TWI_CR) SMBUS Quick Command
#define TWI_SR_SVACC
(TWI_SR) Slave Access (automatically set / reset)
#define TWI_CR_SVDIS
(TWI_CR) TWI Slave Mode Disabled
#define TWI_CWGR_CKDIV(value)
#define TWI_CR_MSEN
(TWI_CR) TWI Master Mode Enabled
uint32_t twi_get_interrupt_mask(Twi *p_twi)
Read TWI interrupt mask.
Definition twi.c:453
void twi_disable_interrupt(Twi *p_twi, uint32_t ul_sources)
Disable TWI interrupts.
Definition twi.c:426
uint8_t twi_read_byte(Twi *p_twi)
Reads a byte from the TWI bus.
Definition twi.c:465
uint32_t twi_slave_write(Twi *p_twi, uint8_t *p_data)
Write data to TWI bus.
Definition twi.c:583
uint32_t twi_slave_read(Twi *p_twi, uint8_t *p_data)
Read data from master.
Definition twi.c:551
#define TWI_CLK_CALC_ARGU
Definition twi.c:77
uint32_t twi_probe(Twi *p_twi, uint8_t uc_slave_addr)
Test if a chip answers a given I2C address.
Definition twi.c:219
void twi_write_byte(Twi *p_twi, uint8_t uc_byte)
Sends a byte of data to one of the TWI slaves on the bus.
Definition twi.c:476
#define I2C_FAST_MODE_SPEED
Definition twi.c:72
uint32_t twi_mk_addr(const uint8_t *addr, int len)
Construct the TWI module address register field.
Definition twi.c:249
void twi_set_slave_addr(Twi *p_twi, uint32_t ul_device_addr)
Set TWI slave address.
Definition twi.c:535
uint32_t twi_get_interrupt_status(Twi *p_twi)
Get TWI interrupt status.
Definition twi.c:441
Pdc * twi_get_pdc_base(Twi *p_twi)
Get TWI PDC base address.
Definition twi.c:623
#define TWI_CLK_DIV_MAX
Definition twi.c:79
void twi_enable_master_mode(Twi *p_twi)
Enable TWI master mode.
Definition twi.c:89
#define TWI_CLK_DIV_MIN
Definition twi.c:80
#define LOW_LEVEL_TIME_LIMIT
Definition twi.c:71
void twi_disable_master_mode(Twi *p_twi)
Disable TWI master mode.
Definition twi.c:104
void twi_enable_interrupt(Twi *p_twi, uint32_t ul_sources)
Enable TWI interrupts.
Definition twi.c:414
#define TWI_WP_KEY_VALUE
Definition twi.c:82
uint32_t twi_set_speed(Twi *p_twi, uint32_t ul_speed, uint32_t ul_mck)
Set the I2C bus speed in conjunction with the clock frequency.
Definition twi.c:156
void twi_enable_slave_mode(Twi *p_twi)
Enable TWI slave mode.
Definition twi.c:486
void twi_reset(Twi *p_twi)
Reset TWI.
Definition twi.c:609
void twi_disable_slave_mode(Twi *p_twi)
Disable TWI slave mode.
Definition twi.c:501
uint32_t twi_master_write(Twi *p_twi, twi_packet_t *p_packet)
Write multiple bytes to a TWI compatible slave device.
Definition twi.c:353
uint32_t twi_master_init(Twi *p_twi, const twi_options_t *p_opt)
Initialize TWI master mode.
Definition twi.c:118
#define TWI_CLK_DIVIDER
Definition twi.c:73
void twi_slave_init(Twi *p_twi, uint32_t ul_device_addr)
Initialize TWI slave mode.
Definition twi.c:513
uint32_t twi_master_read(Twi *p_twi, twi_packet_t *p_packet)
Read multiple bytes from a TWI compatible slave device.
Definition twi.c:278
#define PDC_TWI0
(PDC_TWI0 ) Base Address
Definition sam4sd32c.h:420
#define TWI0
(TWI0 ) Base Address
Definition sam4sd32c.h:419
#define TWI1
(TWI1 ) Base Address
Definition sam4sd32c.h:421
#define PDC_TWI1
(PDC_TWI1 ) Base Address
Definition sam4sd32c.h:422
Twi hardware registers.
__I uint32_t TWI_SR
(Twi Offset: 0x20) Status Register
__I uint32_t TWI_RHR
(Twi Offset: 0x30) Receive Holding Register
__IO uint32_t TWI_CWGR
(Twi Offset: 0x10) Clock Waveform Generator Register
__IO uint32_t TWI_IADR
(Twi Offset: 0x0C) Internal Address Register
__O uint32_t TWI_IDR
(Twi Offset: 0x28) Interrupt Disable Register
__O uint32_t TWI_CR
(Twi Offset: 0x00) Control Register
__O uint32_t TWI_IER
(Twi Offset: 0x24) Interrupt Enable Register
__IO uint32_t TWI_MMR
(Twi Offset: 0x04) Master Mode Register
__O uint32_t TWI_THR
(Twi Offset: 0x34) Transmit Holding Register
__I uint32_t TWI_IMR
(Twi Offset: 0x2C) Interrupt Mask Register
__IO uint32_t TWI_SMR
(Twi Offset: 0x08) Slave Mode Register
uint32_t speed
The baud rate of the TWI bus.
Definition twi.h:78
uint8_t smbus
SMBUS mode (set 1 to use SMBUS quick command, otherwise don't).
Definition twi.h:82
uint32_t master_clk
MCK for TWI.
Definition twi.h:76
uint32_t addr_length
Length of the TWI data address segment (1-3 bytes).
Definition twi.h:92
void * buffer
Where to find the data to be transferred.
Definition twi.h:94
uint32_t length
How many bytes do we want to transfer.
Definition twi.h:96
uint8_t chip
TWI chip address to communicate with.
Definition twi.h:98
uint8_t addr[3]
TWI address/commands to issue to the other chip (node).
Definition twi.h:90
Two-Wire Interface (TWI) driver for SAM.
struct twi_packet twi_packet_t
Information concerning the data transmission.
#define TWI_RECEIVE_NACK
Definition twi.h:62
struct twi_options twi_options_t
Input parameters when initializing the TWI module mode.
#define TWI_TIMEOUT
Time-out value (number of attempts).
Definition twi.h:51
#define TWI_SUCCESS
Return codes for TWI APIs.
Definition twi.h:57
#define TWI_INVALID_ARGUMENT
Definition twi.h:58
#define TWI_ERROR_TIMEOUT
Definition twi.h:66