Quantcast
Viewing latest article 3
Browse Latest Browse All 7

How to use the i2c bus with PIC12f1840 (a simple library)

We have developed this library to use the i2c bus on our 12f1840 development board.

http://www.xappsoftware.com/wordpress/?p=3523

http://www.xappsoftware.com/wordpress/?p=3428

Naturally it can be used also with our PICcoletta board and with other boards which use Microchip PICs. Leave a message to this post if you find useful this library or if you use this library with other PICs.

This library doesn't use interrupts, but only the polling mode (arghh!!!)

The flow goes out from the polling cycle when the flag has been signaled or when the timeout occurs. The timeout is handled using the tmr1 overflow.


(Refer to the Microchip application note AN1355)

We have used the HI-TECH C compiler LITE edition that can be downloaded freely from the Microchip site.

The following procedure initializes the i2c:

<span style="color: #CC6600;">void</span> ini_i2c1(<span style="color: #CC6600;">void</span>)         <span style="color: #7E7E7E;">// init the I2C module on MSSP1</span>
{
&nbsp;&nbsp;TRISA&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;0b00111111;&nbsp;<span style="color: #7E7E7E;">// all input</span>
&nbsp;&nbsp;ANSELA&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;0b00000000;&nbsp;<span style="color: #7E7E7E;">// no analog input    </span>
&nbsp;&nbsp;SSP1ADD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;0&times;03&nbsp;;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #7E7E7E;">// baud rate =  50 khz    SSP1ADD = 79 , Baud rate = 100Khz SPP1ADD = 39 Baud rate 400Khz SSP1ADD = 9</span>
&nbsp;&nbsp;SSP1STAT&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;0&times;80&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #7E7E7E;">// slew rate dis  8 , SMBUS disabled </span>
&nbsp;&nbsp;SSP1CON1&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;0&times;28&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #7E7E7E;">// enable module, I2C master SSP1ADD=baud rate</span>
&nbsp;&nbsp;SSP1CON2&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;0&times;00&nbsp;&nbsp;;&nbsp;
}&nbsp;;

 

As we have already said, all the operations on the i2c bus are controlled using the "polling mode". The procedure that controls the polling is the poll_if_tim1 function:

This function arms a timer and performs a check on the overflow flags and on the SSP1IF flag of the PIR1 register. If the timeout expires the function sets the error variable.

<span style="color: #CC6600;">void</span> poll_if_tim1(<span style="color: #CC6600;">void</span>)
{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TMR1H&nbsp;=&nbsp;~(10000/256)&amp;0xff;          <span class="Apple-style-span" style="color: rgb(126, 126, 126); ">// poll 2 flags: MSSP1IF &amp; T1</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TMR1L&nbsp;=&nbsp;~(10000%256)&amp;0xff;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #7E7E7E;">//  1msec delay</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;T1_ON&nbsp;=&nbsp;1&nbsp;;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #7E7E7E;">//  start timer1</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #CC6600;">while</span>(!(PIR1bits.SSP1IF|T1_OVFL)) ; <span style="color: #7E7E7E;">// wait at least on flag to rise</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #CC6600;">if</span> (T1_OVFL)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gucI2CError&nbsp;=&nbsp;0&times;01;&nbsp;<span style="color: #7E7E7E;">// if timeout, set error flag</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PIR1bits.SSP1IF&nbsp;=&nbsp;0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #7E7E7E;">// in any case, clear all  </span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;T1_OVFL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;0;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;T1_ON&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}&nbsp;&nbsp;&nbsp;

To start or restart the i2c communication we use two equal functions, we use two functions because you can decide to implements differents behaviours in the two cases.

<span style="color: #7E7E7E;">/**&nbsp;start&nbsp;the&nbsp;I2C&nbsp;COMMUNICATION&nbsp;&nbsp;&nbsp;*/</span>
<span style="color: #CC6600;">void</span> i2c_start(<span style="color: #CC6600;">void</span>)             <span style="color: #7E7E7E;">// START I2C communication</span>
{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SSP1CON2bits.SEN&nbsp;=&nbsp;1;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #7E7E7E;">// START bit (cleared by hw in the end)</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;poll_if_tim1()&nbsp;&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;&nbsp;
}&nbsp;
<span style="color: #7E7E7E;">/**&nbsp;restart&nbsp;the&nbsp;I2C&nbsp;COMMUNICATION</span>
<span style="color: #7E7E7E;">&nbsp;*/</span>
<span style="color: #CC6600;">void</span> i2c_restart(<span style="color: #CC6600;">void</span>)           <span style="color: #7E7E7E;">// RESTART I2C communication (change to &#39;reads&#39;)</span>
{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SSP1CON2bits.RSEN&nbsp;=&nbsp;1;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #7E7E7E;">// REPEATED START bit (cleared by hw in the end)</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;poll_if_tim1()&nbsp;&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;&nbsp;
}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

The stop function is very simple, too.

<span style="color: #7E7E7E;">/**&nbsp;Send&nbsp;STOP&nbsp;for&nbsp;the&nbsp;I2C&nbsp;COMMUNICATION</span>
<span style="color: #7E7E7E;">&nbsp;*/</span>
<span style="color: #CC6600;">void</span> i2c_stop(<span style="color: #CC6600;">void</span>)              <span style="color: #7E7E7E;">// STOP I2C communication</span>
{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SSP1CON2bits.PEN&nbsp;=&nbsp;1;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #7E7E7E;">// STOP bit (cleared by hw in the end)</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;poll_if_tim1()&nbsp;&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;&nbsp;
}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

And now the ACK and NACK functions:

<span style="color: #7E7E7E;">/**&nbsp;Send&nbsp;STOP&nbsp;for&nbsp;the&nbsp;I2C&nbsp;COMMUNICATION</span>
<span style="color: #7E7E7E;">&nbsp;*/</span>
<span style="color: #CC6600;">void</span> i2c_stop(<span style="color: #CC6600;">void</span>)              <span style="color: #7E7E7E;">// STOP I2C communication</span>
{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SSP1CON2bits.PEN&nbsp;=&nbsp;1;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #7E7E7E;">// STOP bit (cleared by hw in the end)</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;poll_if_tim1()&nbsp;&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;&nbsp;
}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

Last but not least, the write and read functions:

<span style="color: #7E7E7E;">/**&nbsp;The&nbsp;write&nbsp;function</span>
<span style="color: #7E7E7E;">&nbsp;*/</span>
<span style="color: #CC6600;">void</span> i2c_wr(<span style="color: #CC6600;">unsigned</span> <span style="color: #CC6600;">char</span> i2c_data) <span style="color: #7E7E7E;">// writes a byte in the I2C SLAVE</span>
{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SSP1BUF&nbsp;=&nbsp;i2c_data&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #7E7E7E;">// load char in data buffer ; start streaming</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;poll_if_tim1()&nbsp;&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #7E7E7E;">// poll MSSP1IF with 1msec timeout </span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #CC6600;">if</span>(SSP1CON2bits.ACKSTAT)       <span style="color: #7E7E7E;">// if NOACK from slave </span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gucI2CError&nbsp;=&nbsp;ERR_I2C_FATAL;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #CC6600;">else</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #7E7E7E;">// wonderfull &hellip; I have the pic written correctly</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #7E7E7E;">// if a correct ACK from the slave, do nothing</span>
&nbsp;
<span style="color: #7E7E7E;">/**&nbsp;The&nbsp;read&nbsp;function</span>
<span style="color: #7E7E7E;">&nbsp;*/</span>
<span style="color: #CC6600;">unsigned</span> <span style="color: #CC6600;">char</span>  i2c_rd(<span style="color: #CC6600;">void</span>)
{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #CC6600;">unsigned</span> <span style="color: #CC6600;">char</span> ucByteRead;
&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SSP1CON2bits.RCEN&nbsp;=&nbsp;1&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #7E7E7E;">// enable I2C receive mode(RCEN=0 after 8cks by hw)</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;poll_if_tim1()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #7E7E7E;">// poll MSSP1IF with timeout</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ucByteRead&nbsp;=&nbsp;SSP1BUF&nbsp;&nbsp;&nbsp;&nbsp;;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #CC6600;">return</span> ucByteRead           ;
}&nbsp;&nbsp;

If you found useful this article, please share it using the social buttons below. Thank you in advance.

Gg1


Viewing latest article 3
Browse Latest Browse All 7

Trending Articles