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,12 +1,104 @@
|
||||
#include "common.h"
|
||||
#include "bus/twi.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)
|
||||
{
|
||||
// Set SCL bit rate to 400kHz
|
||||
|
||||
TWSR = 0x00; // TWI status register
|
||||
TWBR = 0x0C; // TWI bit rate register
|
||||
TWSR = 0x00; // TWI status register
|
||||
TWBR = 0x0C; // TWI bit rate register
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "common.h"
|
||||
#include "bus/usart.h"
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
//#include <util/atomic.h>
|
||||
|
||||
@@ -9,4 +9,7 @@
|
||||
void Info(const char *fmt, ...);
|
||||
void Error(const char *fmt, ...);
|
||||
|
||||
#include <util/delay.h>
|
||||
#define Sleep(ms) _delay_ms(ms)
|
||||
|
||||
#endif // MAD_CORE_COMMON_H
|
||||
|
||||
65
src/main.c
65
src/main.c
@@ -3,26 +3,67 @@
|
||||
#include "bus/twi.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();
|
||||
TWI_Init();
|
||||
|
||||
sei();
|
||||
|
||||
Info("Initializing...");
|
||||
Sleep(500);
|
||||
char crb;
|
||||
|
||||
// ADS1115 (ADC)
|
||||
// PCA9546 (Multiplexer TWI)
|
||||
// ATH20 (3x)
|
||||
// BMP280 (3x)
|
||||
|
||||
UNUSED(argc);
|
||||
UNUSED(argv);
|
||||
USART_Init();
|
||||
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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user