This software drives a PCA9675 device via an I2C bus. Included functions allow you to read the device ID, set the IO direction, and read and write from the device.
Source/PCA9675.cpp@0:3331b5950572, 2010-11-23 (annotated)
- Committer:
- DavidGilesHitex
- Date:
- Tue Nov 23 10:59:14 2010 +0000
- Revision:
- 0:3331b5950572
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
DavidGilesHitex | 0:3331b5950572 | 1 | /* C++ Source Code for PCA9675 I2C 16bit IO latch */ |
DavidGilesHitex | 0:3331b5950572 | 2 | /* ********************************************** */ |
DavidGilesHitex | 0:3331b5950572 | 3 | |
DavidGilesHitex | 0:3331b5950572 | 4 | |
DavidGilesHitex | 0:3331b5950572 | 5 | #include "misra_types.h" |
DavidGilesHitex | 0:3331b5950572 | 6 | #include "mbed.h" |
DavidGilesHitex | 0:3331b5950572 | 7 | #include "PCA9675.h" |
DavidGilesHitex | 0:3331b5950572 | 8 | |
DavidGilesHitex | 0:3331b5950572 | 9 | |
DavidGilesHitex | 0:3331b5950572 | 10 | |
DavidGilesHitex | 0:3331b5950572 | 11 | |
DavidGilesHitex | 0:3331b5950572 | 12 | /* Constructor */ |
DavidGilesHitex | 0:3331b5950572 | 13 | PCA9675::PCA9675(I2C *Selected_I2C_Channel, uint8_t Slave_Address) |
DavidGilesHitex | 0:3331b5950572 | 14 | { |
DavidGilesHitex | 0:3331b5950572 | 15 | My_Local_I2C = Selected_I2C_Channel; |
DavidGilesHitex | 0:3331b5950572 | 16 | My_Lcoal_Slave_Address = Slave_Address; |
DavidGilesHitex | 0:3331b5950572 | 17 | } |
DavidGilesHitex | 0:3331b5950572 | 18 | |
DavidGilesHitex | 0:3331b5950572 | 19 | /* Destructor */ |
DavidGilesHitex | 0:3331b5950572 | 20 | PCA9675::~PCA9675() |
DavidGilesHitex | 0:3331b5950572 | 21 | { |
DavidGilesHitex | 0:3331b5950572 | 22 | } |
DavidGilesHitex | 0:3331b5950572 | 23 | |
DavidGilesHitex | 0:3331b5950572 | 24 | |
DavidGilesHitex | 0:3331b5950572 | 25 | |
DavidGilesHitex | 0:3331b5950572 | 26 | /* Setup and configure the I/O latch */ |
DavidGilesHitex | 0:3331b5950572 | 27 | sint32_t PCA9675::init(uint8_t Port0_Direction, uint8_t Port1_Direction) |
DavidGilesHitex | 0:3331b5950572 | 28 | { |
DavidGilesHitex | 0:3331b5950572 | 29 | sint32_t Ack_Status = eI2C_ACK; |
DavidGilesHitex | 0:3331b5950572 | 30 | |
DavidGilesHitex | 0:3331b5950572 | 31 | Ack_Status = reset(); /* Reset the device */ |
DavidGilesHitex | 0:3331b5950572 | 32 | My_Local_Port0_Direction = Port0_Direction; /* Keep a copy of the port0 direction */ |
DavidGilesHitex | 0:3331b5950572 | 33 | My_Local_Port1_Direction = Port1_Direction; /* Keep a copy of the port1 direction */ |
DavidGilesHitex | 0:3331b5950572 | 34 | |
DavidGilesHitex | 0:3331b5950572 | 35 | if (Ack_Status == eI2C_ACK) |
DavidGilesHitex | 0:3331b5950572 | 36 | { |
DavidGilesHitex | 0:3331b5950572 | 37 | Ack_Status = write_data(Port0_Direction, Port1_Direction); /* This configures the I/O direction: each bit: 0=output, 1=inout */ |
DavidGilesHitex | 0:3331b5950572 | 38 | } |
DavidGilesHitex | 0:3331b5950572 | 39 | |
DavidGilesHitex | 0:3331b5950572 | 40 | return Ack_Status; |
DavidGilesHitex | 0:3331b5950572 | 41 | } |
DavidGilesHitex | 0:3331b5950572 | 42 | |
DavidGilesHitex | 0:3331b5950572 | 43 | |
DavidGilesHitex | 0:3331b5950572 | 44 | |
DavidGilesHitex | 0:3331b5950572 | 45 | |
DavidGilesHitex | 0:3331b5950572 | 46 | /* Reset the device */ |
DavidGilesHitex | 0:3331b5950572 | 47 | sint32_t PCA9675::reset() |
DavidGilesHitex | 0:3331b5950572 | 48 | { |
DavidGilesHitex | 0:3331b5950572 | 49 | sint32_t Ack_Status = eI2C_ACK; |
DavidGilesHitex | 0:3331b5950572 | 50 | sint8_t reset_command = ePCA9675_RESET_COMMAND; /* Reset command following a general call, address 0 will reset the device */ |
DavidGilesHitex | 0:3331b5950572 | 51 | |
DavidGilesHitex | 0:3331b5950572 | 52 | Ack_Status = My_Local_I2C -> write(ePCA9675_RESET_ADDRESS << 1, &reset_command, 1, eI2C_NO_REPEATED_START); |
DavidGilesHitex | 0:3331b5950572 | 53 | |
DavidGilesHitex | 0:3331b5950572 | 54 | return Ack_Status; |
DavidGilesHitex | 0:3331b5950572 | 55 | } |
DavidGilesHitex | 0:3331b5950572 | 56 | |
DavidGilesHitex | 0:3331b5950572 | 57 | |
DavidGilesHitex | 0:3331b5950572 | 58 | /* Write two byte of data to the device */ |
DavidGilesHitex | 0:3331b5950572 | 59 | sint32_t PCA9675::write_data(uint8_t port0_payload, uint8_t port1_payload) |
DavidGilesHitex | 0:3331b5950572 | 60 | { |
DavidGilesHitex | 0:3331b5950572 | 61 | sint32_t Ack_Status = eI2C_ACK; |
DavidGilesHitex | 0:3331b5950572 | 62 | sint8_t tx_array[2]; /* Local array of data to be transmitted */ |
DavidGilesHitex | 0:3331b5950572 | 63 | |
DavidGilesHitex | 0:3331b5950572 | 64 | /* If we try and write a 0/1 to a pin that is designated an input we must force the state to a 1(input) */ |
DavidGilesHitex | 0:3331b5950572 | 65 | /* as the device is quasi birectional */ |
DavidGilesHitex | 0:3331b5950572 | 66 | /* This is to avoid turning the pin from a designated input into an output by mistake */ |
DavidGilesHitex | 0:3331b5950572 | 67 | /* If the pin is designated as input and we have logic 1 on the input we and indvertantly write a 0 to it */ |
DavidGilesHitex | 0:3331b5950572 | 68 | /* then we will have a large current flow input the pin */ |
DavidGilesHitex | 0:3331b5950572 | 69 | /* Hence the 'or' block below prevents unwanted damage to the pin */ |
DavidGilesHitex | 0:3331b5950572 | 70 | /* Quasi direction is: 1 = input, 0 = output */ |
DavidGilesHitex | 0:3331b5950572 | 71 | port0_payload = (port0_payload | My_Local_Port0_Direction); |
DavidGilesHitex | 0:3331b5950572 | 72 | port0_payload = (port1_payload | My_Local_Port1_Direction); |
DavidGilesHitex | 0:3331b5950572 | 73 | |
DavidGilesHitex | 0:3331b5950572 | 74 | tx_array[ePCA9675_PORT0] = port0_payload; /* First is for Port 0 */ |
DavidGilesHitex | 0:3331b5950572 | 75 | tx_array[ePCA9675_PORT1] = port1_payload; /* Second is for Port 1 */ |
DavidGilesHitex | 0:3331b5950572 | 76 | |
DavidGilesHitex | 0:3331b5950572 | 77 | Ack_Status = My_Local_I2C -> write(My_Lcoal_Slave_Address << 1, tx_array, 2, eI2C_NO_REPEATED_START); |
DavidGilesHitex | 0:3331b5950572 | 78 | return Ack_Status; |
DavidGilesHitex | 0:3331b5950572 | 79 | } |
DavidGilesHitex | 0:3331b5950572 | 80 | |
DavidGilesHitex | 0:3331b5950572 | 81 | |
DavidGilesHitex | 0:3331b5950572 | 82 | /* Read two bytes from the device */ |
DavidGilesHitex | 0:3331b5950572 | 83 | sint32_t PCA9675::read_data(uint8_t *read_port0, uint8_t *read_port1) |
DavidGilesHitex | 0:3331b5950572 | 84 | { |
DavidGilesHitex | 0:3331b5950572 | 85 | sint32_t Ack_Status = eI2C_ACK; |
DavidGilesHitex | 0:3331b5950572 | 86 | sint8_t rx_array[2]; /* Local reception array */ |
DavidGilesHitex | 0:3331b5950572 | 87 | |
DavidGilesHitex | 0:3331b5950572 | 88 | Ack_Status = My_Local_I2C -> read(My_Lcoal_Slave_Address << 1, rx_array, 2, eI2C_NO_REPEATED_START); |
DavidGilesHitex | 0:3331b5950572 | 89 | |
DavidGilesHitex | 0:3331b5950572 | 90 | *read_port0 = rx_array[ePCA9675_PORT0]; /* transfer data back to pointer */ |
DavidGilesHitex | 0:3331b5950572 | 91 | *read_port1 = rx_array[ePCA9675_PORT1]; /* transfer data back to pointer */ |
DavidGilesHitex | 0:3331b5950572 | 92 | return Ack_Status; |
DavidGilesHitex | 0:3331b5950572 | 93 | } |
DavidGilesHitex | 0:3331b5950572 | 94 | |
DavidGilesHitex | 0:3331b5950572 | 95 | |
DavidGilesHitex | 0:3331b5950572 | 96 | /* Read the device ID */ |
DavidGilesHitex | 0:3331b5950572 | 97 | sint32_t PCA9675::read_device_ID(uint8_t *manufacturer, uint16_t *part_ident, uint8_t *die_revision) |
DavidGilesHitex | 0:3331b5950572 | 98 | |
DavidGilesHitex | 0:3331b5950572 | 99 | { |
DavidGilesHitex | 0:3331b5950572 | 100 | sint32_t Ack_Status = eI2C_ACK; |
DavidGilesHitex | 0:3331b5950572 | 101 | sint8_t rx_array[3] = {0,0,0}; |
DavidGilesHitex | 0:3331b5950572 | 102 | uint32_t temp_value = 0; |
DavidGilesHitex | 0:3331b5950572 | 103 | sint8_t tx_array = (My_Lcoal_Slave_Address << 1); |
DavidGilesHitex | 0:3331b5950572 | 104 | |
DavidGilesHitex | 0:3331b5950572 | 105 | |
DavidGilesHitex | 0:3331b5950572 | 106 | Ack_Status = My_Local_I2C -> write(0xF8, &tx_array, 1, eI2C_REPEATED_START); |
DavidGilesHitex | 0:3331b5950572 | 107 | Ack_Status = My_Local_I2C -> read(0xF9, rx_array, 3, eI2C_NO_REPEATED_START); |
DavidGilesHitex | 0:3331b5950572 | 108 | |
DavidGilesHitex | 0:3331b5950572 | 109 | temp_value = rx_array[0]; |
DavidGilesHitex | 0:3331b5950572 | 110 | temp_value = (temp_value << 8); |
DavidGilesHitex | 0:3331b5950572 | 111 | |
DavidGilesHitex | 0:3331b5950572 | 112 | temp_value = (temp_value | rx_array[1]); |
DavidGilesHitex | 0:3331b5950572 | 113 | temp_value = (temp_value << 8); |
DavidGilesHitex | 0:3331b5950572 | 114 | |
DavidGilesHitex | 0:3331b5950572 | 115 | temp_value = (temp_value | rx_array[2]); |
DavidGilesHitex | 0:3331b5950572 | 116 | |
DavidGilesHitex | 0:3331b5950572 | 117 | |
DavidGilesHitex | 0:3331b5950572 | 118 | *die_revision = (uint8_t) (temp_value & 0x00000003); /* 3 LSB bits are die revision */ |
DavidGilesHitex | 0:3331b5950572 | 119 | temp_value = (temp_value >> 3); |
DavidGilesHitex | 0:3331b5950572 | 120 | |
DavidGilesHitex | 0:3331b5950572 | 121 | *part_ident = (uint16_t) (temp_value & 0x00001FFF); /* Next 13 bits are part identification */ |
DavidGilesHitex | 0:3331b5950572 | 122 | temp_value = (temp_value >> 13); |
DavidGilesHitex | 0:3331b5950572 | 123 | |
DavidGilesHitex | 0:3331b5950572 | 124 | *manufacturer = (uint8_t) (temp_value & 0x000000FF); /* Next 8 bits are manufacturers name */ |
DavidGilesHitex | 0:3331b5950572 | 125 | |
DavidGilesHitex | 0:3331b5950572 | 126 | return Ack_Status; |
DavidGilesHitex | 0:3331b5950572 | 127 | } |
DavidGilesHitex | 0:3331b5950572 | 128 | |
DavidGilesHitex | 0:3331b5950572 | 129 | |
DavidGilesHitex | 0:3331b5950572 | 130 | |
DavidGilesHitex | 0:3331b5950572 | 131 | |
DavidGilesHitex | 0:3331b5950572 | 132 | /* Read the configured slave address */ |
DavidGilesHitex | 0:3331b5950572 | 133 | uint8_t PCA9675::read_slave_address() |
DavidGilesHitex | 0:3331b5950572 | 134 | { |
DavidGilesHitex | 0:3331b5950572 | 135 | return My_Lcoal_Slave_Address; |
DavidGilesHitex | 0:3331b5950572 | 136 | } |
DavidGilesHitex | 0:3331b5950572 | 137 | |
DavidGilesHitex | 0:3331b5950572 | 138 | |
DavidGilesHitex | 0:3331b5950572 | 139 |