Handle I2C multiplexer channel selection
This commit is contained in:
BIN
docs/PCA9546-02.pdf
Executable file
BIN
docs/PCA9546-02.pdf
Executable file
Binary file not shown.
@@ -1,5 +1,17 @@
|
|||||||
|
#include "common.h"
|
||||||
#include "bus/twi.h"
|
#include "bus/twi.h"
|
||||||
|
|
||||||
#include <avr/io.h>
|
#include <avr/io.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#define TW_START 0x08
|
||||||
|
#define TW_REP_START 0x10
|
||||||
|
#define TW_MT_SLA_ACK 0x18
|
||||||
|
#define TW_MT_SLA_NACK 0x20
|
||||||
|
#define TW_MT_DATA_ACK 0x28
|
||||||
|
#define TW_MR_SLA_ACK 0x40
|
||||||
|
#define TW_MR_SLA_NACK 0x48
|
||||||
|
#define TW_MR_DATA_ACK 0x50
|
||||||
|
|
||||||
int TWI_Init(void)
|
int TWI_Init(void)
|
||||||
{
|
{
|
||||||
@@ -10,3 +22,83 @@ int TWI_Init(void)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int TWI_Start(char addr, char mode)
|
||||||
|
{
|
||||||
|
unsigned int status;
|
||||||
|
|
||||||
|
assert(mode == 0 || mode == 1);
|
||||||
|
|
||||||
|
// Send start condition
|
||||||
|
|
||||||
|
TWCR = (1 << TWEN) // Enable TWI
|
||||||
|
| (1 << TWINT) // Clear interrupt flag
|
||||||
|
| (1 << TWSTA); // Send start condition
|
||||||
|
|
||||||
|
// Wait until start condition sent
|
||||||
|
|
||||||
|
while ((TWCR & (1 << TWINT)) == 0);
|
||||||
|
if ((TWSR & 0xf8) != TW_START)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
// Send slave address
|
||||||
|
|
||||||
|
addr = addr << 1; // Lowest bit for mode
|
||||||
|
TWDR = addr + mode; // Mode 0=R, 1=W
|
||||||
|
TWCR = (1 << TWEN) // Enable TWI
|
||||||
|
| (1 << TWINT); // Clear interrupt flag
|
||||||
|
|
||||||
|
// Wait until slave address sent
|
||||||
|
|
||||||
|
while ((TWCR & (1 << TWINT)) == 0);
|
||||||
|
status = TWSR & 0xF8;
|
||||||
|
|
||||||
|
if ((mode == 0 && status != TW_MT_SLA_ACK) ||
|
||||||
|
(mode == 1 && status != TW_MR_SLA_ACK))
|
||||||
|
return -2;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int TWI_Write(char data)
|
||||||
|
{
|
||||||
|
TWDR = data;
|
||||||
|
TWCR = (1 << TWEN) // Enable TWI
|
||||||
|
| (1 << TWINT); // Clear interrupt flag
|
||||||
|
|
||||||
|
while ((TWCR & (1 << TWINT)) == 0);
|
||||||
|
|
||||||
|
if ((TWSR & 0xF8) != TW_MT_DATA_ACK)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int TWI_Wait_ACK(void)
|
||||||
|
{
|
||||||
|
unsigned int status;
|
||||||
|
|
||||||
|
while ((TWCR & (1 << TWINT)) == 0);
|
||||||
|
status = TWSR & 0xF8;
|
||||||
|
|
||||||
|
if (status != TW_MT_DATA_ACK &&
|
||||||
|
status != TW_MR_DATA_ACK)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int TWI_Stop(void)
|
||||||
|
{
|
||||||
|
// Send stop condition
|
||||||
|
|
||||||
|
TWCR = (1 << TWEN) // Enable TWI
|
||||||
|
| (1 << TWINT) // Clear interrupt flag
|
||||||
|
| (1 << TWSTO); // Send stop condition
|
||||||
|
|
||||||
|
// Wait until stop condition sent
|
||||||
|
|
||||||
|
while (TWCR & (1 << TWSTO));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,5 +2,9 @@
|
|||||||
#define MAD_CORE_BUS_TWI_H
|
#define MAD_CORE_BUS_TWI_H
|
||||||
|
|
||||||
int TWI_Init(void);
|
int TWI_Init(void);
|
||||||
|
int TWI_Start(char addr, char mode);
|
||||||
|
int TWI_Write(char data);
|
||||||
|
int TWI_Wait_ACK(void);
|
||||||
|
int TWI_Stop(void);
|
||||||
|
|
||||||
#endif // MAD_CORE_BUS_TWI_H
|
#endif // MAD_CORE_BUS_TWI_H
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "bus/usart.h"
|
#include "bus/usart.h"
|
||||||
|
|
||||||
#include <avr/io.h>
|
#include <avr/io.h>
|
||||||
#include <avr/interrupt.h>
|
#include <avr/interrupt.h>
|
||||||
//#include <util/atomic.h>
|
//#include <util/atomic.h>
|
||||||
|
|||||||
@@ -9,4 +9,7 @@
|
|||||||
void Info(const char *fmt, ...);
|
void Info(const char *fmt, ...);
|
||||||
void Error(const char *fmt, ...);
|
void Error(const char *fmt, ...);
|
||||||
|
|
||||||
|
#include <util/delay.h>
|
||||||
|
#define Sleep(ms) _delay_ms(ms)
|
||||||
|
|
||||||
#endif // MAD_CORE_COMMON_H
|
#endif // MAD_CORE_COMMON_H
|
||||||
|
|||||||
65
src/main.c
65
src/main.c
@@ -3,26 +3,67 @@
|
|||||||
#include "bus/twi.h"
|
#include "bus/twi.h"
|
||||||
|
|
||||||
#include <avr/interrupt.h>
|
#include <avr/interrupt.h>
|
||||||
#include <util/delay.h>
|
|
||||||
#define Sleep(ms) _delay_ms(ms)
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(void)
|
||||||
{
|
{
|
||||||
USART_Init();
|
char crb;
|
||||||
TWI_Init();
|
|
||||||
|
|
||||||
sei();
|
|
||||||
|
|
||||||
Info("Initializing...");
|
|
||||||
Sleep(500);
|
|
||||||
|
|
||||||
// ADS1115 (ADC)
|
// ADS1115 (ADC)
|
||||||
// PCA9546 (Multiplexer TWI)
|
// PCA9546 (Multiplexer TWI)
|
||||||
// ATH20 (3x)
|
// ATH20 (3x)
|
||||||
// BMP280 (3x)
|
// BMP280 (3x)
|
||||||
|
|
||||||
UNUSED(argc);
|
USART_Init();
|
||||||
UNUSED(argv);
|
TWI_Init();
|
||||||
|
|
||||||
|
sei();
|
||||||
|
|
||||||
|
Info("Initializing...");
|
||||||
|
|
||||||
|
// PCA9546 I2C Multiplexer
|
||||||
|
// =======================
|
||||||
|
|
||||||
|
TWI_Stop();
|
||||||
|
|
||||||
|
// Excerpts taken from the PCA9546A datasheet:
|
||||||
|
// https://www.ti.com/lit/ds/symlink/pca9546a.pdf
|
||||||
|
|
||||||
|
// Following a start condition, the bus master
|
||||||
|
// must output the address of the slave it is
|
||||||
|
// accessing.
|
||||||
|
|
||||||
|
// 7 6 5 4 | 3 2 1 0
|
||||||
|
// 1 1 1 0 | A2 A1 A0 RW
|
||||||
|
// FIXED_____ | SELECTABLE____
|
||||||
|
|
||||||
|
TWI_Start(0x70, 0);
|
||||||
|
TWI_Wait_ACK();
|
||||||
|
|
||||||
|
// Following the successful acknowledgment of
|
||||||
|
// the slave address, the bus master sends a byte
|
||||||
|
// which is stored in the control register.
|
||||||
|
|
||||||
|
// 7 6 5 4 | 3 2 1 0
|
||||||
|
// X X X X | B3 B2 B1 B0
|
||||||
|
// | CHANNEL_______
|
||||||
|
|
||||||
|
crb = 0x01; // Channel 0 | 00000001
|
||||||
|
// = 0x02 // Channel 1 | 00000010
|
||||||
|
// = 0x04 // Channel 2 | 00000100
|
||||||
|
// = 0x08 // Channel 3 | 00001000
|
||||||
|
|
||||||
|
TWI_Write(crb);
|
||||||
|
|
||||||
|
// When a channel is selected, the channel
|
||||||
|
// becomes active after a stop condition has been
|
||||||
|
// placed on the I2C bus. A stop condition always
|
||||||
|
// must occur right after the acknowledge cycle.
|
||||||
|
|
||||||
|
TWI_Wait_ACK();
|
||||||
|
TWI_Stop();
|
||||||
|
|
||||||
|
Info("Switched to TWI channel 0.");
|
||||||
|
Sleep(500);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user