• Main Page
  • Modules
  • Index
  • File List
  • Globals

hal/nrf24le1/hal_w2.c

Go to the documentation of this file.
00001 /* Copyright (c) 2009 Nordic Semiconductor. All Rights Reserved.
00002  *
00003  * The information contained herein is confidential property of Nordic 
00004  * Semiconductor ASA.Terms and conditions of usage are described in detail 
00005  * in NORDIC SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT. 
00006  *
00007  * Licensees are granted free, non-transferable use of the information. NO
00008  * WARRENTY of ANY KIND is provided. This heading must NOT be removed from
00009  * the file.
00010  *              
00011  * $LastChangedRevision: 2503 $
00012  */
00013 
00018 #include <stdint.h>
00019 #include <stdbool.h>
00020 
00021 #include "nrf24le1.h"
00022 #include "nordic_common.h"
00023 #include "hal_w2.h"
00024 #include "hal_delay.h"
00025 
00026 #define BROADCAST_ENABLE      7     // W2CON0 register bit 7
00027 #define CLOCK_STOP            6     // W2CON0 register bit 6
00028 #define X_STOP                5     // W2CON0 register bit 5
00029 #define X_START               4     // W2CON0 register bit 4
00030 #define CLOCK_FREQUENCY_1     3     // W2CON0 register bit 3
00031 #define CLOCK_FREQUENCY_0     2     // W2CON0 register bit 2
00032 #define MASTER_SELECT         1     // W2CON0 register bit 1
00033 #define WIRE_2_ENABLE         0     // W2CON0 register bit 0
00034 
00035 void hal_w2_soft_reset();
00036 
00037 /* Slave specific functions */
00038 
00039 void hal_w2_respond_to_gen_adr(bool resp_gen)
00040 { 
00041   if(resp_gen)
00042   {                                                                   
00043     W2CON0 = W2CON0 | (1 << BROADCAST_ENABLE);  // Set "broadcastEnable" bit
00044   }
00045   else
00046   {
00047     W2CON0 = W2CON0 & ~(1 << BROADCAST_ENABLE); // Clear "broadcastEnable" bit
00048   }
00049 }
00050 
00051 void hal_w2_alter_clock(bool alt_clk)
00052 {
00053   if(alt_clk)                         
00054   {
00055     W2CON0 = W2CON0 | (1 << CLOCK_STOP);      // Set "clockStop" bit
00056   }
00057   else
00058   {
00059     W2CON0 = W2CON0 & ~(1 << CLOCK_STOP);     // Clear "clockStop" bit
00060   }
00061 }
00062 
00063 void hal_w2_irq_stop_cond_enable(bool stop_cond)
00064 { 
00065   if(stop_cond)
00066   {                                                                  
00067     W2CON0 = W2CON0 & ~(1 << X_STOP);         // Clear "xStop" bit
00068   }
00069   else
00070   {
00071     W2CON0 = W2CON0 | (1 << X_STOP);          // Set "xStop" bit
00072   }
00073 }
00074 
00075 void hal_w2_irq_adr_match_enable(bool addr_match)
00076 {
00077   if(addr_match)
00078   {
00079     W2CON0 = W2CON0 & ~(1 << X_START);        // Clear "xStart" bit
00080   }
00081   else
00082   {
00083     W2CON0 = W2CON0 | (1 << X_START);         // Set "xStart" bit
00084   }
00085 }
00086 
00087 void hal_w2_set_slave_address(uint8_t address)
00088 {
00089   W2SADR = (address & 0x7F);                  // Set 7 bit adress of the slave
00090 }
00091 
00092 /* General functions */
00093 
00094 void hal_w2_set_clk_freq(hal_w2_clk_freq_t freq)
00095 {                                             
00096   W2CON0 = (W2CON0 & 0xF3) | (((uint8_t)freq) << CLOCK_FREQUENCY_0);       
00097 }                                             // Update "clockFrequency" bits
00098 
00099 void hal_w2_set_op_mode(hal_w2_op_mode_t mode)
00100 {
00101   if(mode == HAL_W2_MASTER)                   // Check for master mode
00102   {                                                                  
00103     W2CON0 = W2CON0 | (1 << MASTER_SELECT);   // Set "masterSelect" bit
00104   }
00105   else
00106   {
00107     W2CON0 = W2CON0 & ~(1 << MASTER_SELECT);  // Clear "masterSelect" bit
00108   }
00109 }
00110 
00111 void hal_w2_enable(bool en)
00112 { 
00113   if(en)
00114   {
00115     W2CON0 = W2CON0 | (1 << WIRE_2_ENABLE);   // Set "wire2Enable" bit
00116   }
00117   else
00118   {
00119     W2CON0 = W2CON0 & ~(1 << WIRE_2_ENABLE);  // Clear "wire2Enable" bit
00120   }
00121 }
00122 
00123 void hal_w2_all_irq_enable(bool irq)
00124 { /* In this function the standard "read-modify-write" is not used because
00125      bit 4:0 (the status bits) in W2CON1 are cleared when read. These bits
00126      are read only so they can not be modified. */
00127   if(irq)
00128   {
00129     W2CON1 = ~(BIT_5);                        // Clear "maskIrq" bit
00130   }
00131   else
00132   {
00133     W2CON1 = BIT_5;                           // Set "maskIrq" bit
00134   }
00135 }
00136 
00137 void hal_w2_configure_master(hal_w2_clk_freq_t mode)
00138 {
00139   hal_w2_enable(true);
00140   hal_w2_set_clk_freq(mode);
00141   hal_w2_set_op_mode(HAL_W2_MASTER);
00142 
00143   INTEXP |= 0x04;                         // Enable 2 wire interrupts
00144   W2CON1 = 0x00;
00145   hal_w2_all_irq_enable(true);             // Enable interrupts in the 2-wire  
00146   SPIF = 0;
00147 }
00148 
00149 uint8_t hal_w2_wait_data_ready(void)
00150 {
00151   uint32_t timeout_counter = 0x0FF;
00152   uint8_t w2_status;
00153   bool data_ready;
00154   bool nack_received;
00155 
00156   do
00157   {
00158     w2_status = W2CON1;
00159     data_ready = (w2_status & W2CON1_FLAG_DATA_READY);
00160     nack_received = (w2_status & W2CON1_FLAG_NACK);
00161     delay_us(10);
00162   } while (!data_ready);
00163 
00164 
00165   return w2_status;
00166 }
00167 
00168 bool hal_w2_init_transfer(uint8_t address, hal_w2_direction_t direction)
00169 {
00170   uint8_t w2_status;
00171 
00172   HAL_W2_ISSUE_START_COND;
00173   HAL_W2_WRITE((address << 1) | (uint8_t)direction);
00174 
00175   w2_status = hal_w2_wait_data_ready();
00176 
00177   if (w2_status & W2CON1_FLAG_NACK)
00178   {
00179     return false; // NACK received from slave or timeout
00180   }
00181   else
00182   {
00183     return true; // ACK received from slave
00184   }
00185 }
00186 
00187 bool hal_w2_write(uint8_t address, const uint8_t *data_ptr, uint8_t data_len)
00188 {
00189   bool ack_received;
00190   ack_received = hal_w2_init_transfer(address, HAL_W2_DIR_WRITE);
00191 
00192   while (data_len-- > 0 && ack_received == true)
00193   {
00194     uint8_t w2_status;
00195     HAL_W2_WRITE(*data_ptr++);
00196     w2_status = hal_w2_wait_data_ready();
00197     if (w2_status & W2CON1_FLAG_NACK)
00198     {
00199       ack_received = false;
00200     }
00201   }
00202 
00203   HAL_W2_ISSUE_STOP_COND;
00204 
00205   return ack_received;
00206 }
00207 
00208 bool hal_w2_read(uint8_t address, uint8_t *data_ptr, uint8_t data_len)
00209 {
00210   uint8_t w2_status;
00211   bool ack_received;
00212   
00213   ack_received = hal_w2_init_transfer(address, HAL_W2_DIR_READ);
00214 
00215   if (ack_received == false) 
00216   {
00217     // This situation (NACK received on bus while trying to read from a slave) leads to a deadlock in the 2-wire interface. 
00218     hal_w2_soft_reset(); // Workaround for the deadlock
00219   }
00220 
00221 
00222   while (data_len-- && ack_received)
00223   {
00224     if (data_len == 0)
00225     {
00226       HAL_W2_ISSUE_STOP_COND;
00227     }
00228 
00229     w2_status = hal_w2_wait_data_ready();
00230 
00231     *data_ptr++ = HAL_W2_READ();
00232     ack_received = !(w2_status & W2CON1_FLAG_NACK);
00233   }
00234 
00235   return ack_received;  
00236 }
00237 
00238 void hal_w2_soft_reset()
00239 {
00240 #ifndef W2_SOFT_RESET_NOT_AVAILABLE
00241   uint8_t pulsecount, w2_freq;
00242 
00243   // Store the selected 2-wire frequency 
00244   w2_freq = W2CON0 & 0x0C;
00245   // Prepare the GPIO's to take over SDA & SCL
00246   HAL_W2_CLEAR_SDA_SCL;
00247   HAL_W2_OVERRIDE_SDA_SCL(1, 1);
00248   //P0DIR = 0xFF;
00249   
00250   // Reset 2-wire. SCL goes high.
00251   W2CON0 = 0x03;
00252   W2CON0 = 0x07;
00253   
00254   // Disable 2-wire.
00255   W2CON0 = 0x06;
00256   
00257   // SDA and SCL are now under software control, and both are high. 
00258   // Complete first SCL pulse.
00259   //P0DIR = 0xEF;
00260   HAL_W2_OVERRIDE_SDA_SCL(1, 0);
00261   
00262   // SCL low
00263   delay_us(5);
00264   //P0DIR = 0xCF;
00265   HAL_W2_OVERRIDE_SDA_SCL(0, 0);
00266   
00267   // SDA low
00268   // Create SCL pulses for 7 more data bits and ACK/NACK
00269   delay_us(5);
00270   for( pulsecount = 0; pulsecount < 8; pulsecount++ )
00271   {
00272     //P0DIR = 0xDF;
00273     HAL_W2_OVERRIDE_SDA_SCL(0, 1);
00274     delay_us(5);
00275     //P0DIR = 0xCF;
00276     HAL_W2_OVERRIDE_SDA_SCL(0, 0);
00277     delay_us(5);
00278   }
00279   
00280   // Generating stop condition by driving SCL high
00281   delay_us(5);
00282   //P0DIR = 0xDF;
00283   HAL_W2_OVERRIDE_SDA_SCL(0, 1);
00284   
00285   // Drive SDA high
00286   delay_us(5);
00287   //P0DIR = 0xFF;
00288   HAL_W2_OVERRIDE_SDA_SCL(1, 1);
00289   
00290   // Work-around done. Return control to 2-wire.
00291   W2CON0 = 0x07;
00292   
00293   // Reset 2-wire and return to master mode at the frequency selected before calling this function
00294   W2CON0 = 0x03;
00295   W2CON0 = 0x03 | w2_freq;
00296 #endif
00297 }

Generated on Fri Apr 20 2012 14:11:45 for nRFGo SDK by  doxygen 1.7.2