mirror of
https://github.com/nicolai86/ErgoDox-EZ.git
synced 2026-05-06 03:18:58 -07:00
add atmega168 i2c source
the atmega168 acts as the FPGA used in the original ErgoDox EZ shine. It reads the RGBW data via I2C and sets it to the LEDs once all data is received.
This commit is contained in:
Executable
+264
@@ -0,0 +1,264 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
*
|
||||||
|
* Atmel Corporation
|
||||||
|
*
|
||||||
|
* File : TWI_Slave.c
|
||||||
|
* Compiler : IAR EWAAVR 2.28a/3.10c
|
||||||
|
* Revision : $Revision: 2475 $
|
||||||
|
* Date : $Date: 2007-09-20 12:00:43 +0200 (to, 20 sep 2007) $
|
||||||
|
* Updated by : $Author: mlarsson $
|
||||||
|
*
|
||||||
|
* Support mail : avr@atmel.com
|
||||||
|
*
|
||||||
|
* Supported devices : All devices with a TWI module can be used.
|
||||||
|
* The example is written for the ATmega16
|
||||||
|
*
|
||||||
|
* AppNote : AVR311 - TWI Slave Implementation
|
||||||
|
*
|
||||||
|
* Description : This is sample driver to AVRs TWI module.
|
||||||
|
* It is interupt driveren. All functionality is controlled through
|
||||||
|
* passing information to and from functions. Se main.c for samples
|
||||||
|
* of how to use the driver.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
/*! \page MISRA
|
||||||
|
*
|
||||||
|
* General disabling of MISRA rules:
|
||||||
|
* * (MISRA C rule 1) compiler is configured to allow extensions
|
||||||
|
* * (MISRA C rule 111) bit fields shall only be defined to be of type unsigned int or signed int
|
||||||
|
* * (MISRA C rule 37) bitwise operations shall not be performed on signed integer types
|
||||||
|
* As it does not work well with 8bit architecture and/or IAR
|
||||||
|
|
||||||
|
* Other disabled MISRA rules
|
||||||
|
* * (MISRA C rule 109) use of union - overlapping storage shall not be used
|
||||||
|
* * (MISRA C rule 61) every non-empty case clause in a switch statement shall be terminated with a break statement
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include <avr/interrupt.h>
|
||||||
|
#include "TWI_slave.h"
|
||||||
|
|
||||||
|
static unsigned char TWI_buf[TWI_BUFFER_SIZE]; // Transceiver buffer. Set the size in the header file
|
||||||
|
static unsigned char TWI_msgSize = 0; // Number of bytes to be transmitted.
|
||||||
|
static unsigned char TWI_state = TWI_NO_STATE; // State byte. Default set to TWI_NO_STATE.
|
||||||
|
|
||||||
|
// This is true when the TWI is in the middle of a transfer
|
||||||
|
// and set to false when all bytes have been transmitted/received
|
||||||
|
// Also used to determine how deep we can sleep.
|
||||||
|
static unsigned char TWI_busy = 0;
|
||||||
|
|
||||||
|
union TWI_statusReg_t TWI_statusReg = {0}; // TWI_statusReg is defined in TWI_Slave.h
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
Call this function to set up the TWI slave to its initial standby state.
|
||||||
|
Remember to enable interrupts from the main application after initializing the TWI.
|
||||||
|
Pass both the slave address and the requrements for triggering on a general call in the
|
||||||
|
same byte. Use e.g. this notation when calling this function:
|
||||||
|
TWI_Slave_Initialise( (TWI_slaveAddress<<TWI_ADR_BITS) | (TRUE<<TWI_GEN_BIT) );
|
||||||
|
The TWI module is configured to NACK on any requests. Use a TWI_Start_Transceiver function to
|
||||||
|
start the TWI.
|
||||||
|
****************************************************************************/
|
||||||
|
void TWI_Slave_Initialise(unsigned char TWI_ownAddress)
|
||||||
|
{
|
||||||
|
TWAR = TWI_ownAddress; // Set own TWI slave address. Accept TWI General Calls.
|
||||||
|
TWCR = (1 << TWEN) | // Enable TWI-interface and release TWI pins.
|
||||||
|
(0 << TWIE) | (0 << TWINT) | // Disable TWI Interrupt.
|
||||||
|
(0 << TWEA) | (0 << TWSTA) | (0 << TWSTO) | // Do not ACK on any requests, yet.
|
||||||
|
(0 << TWWC); //
|
||||||
|
TWI_busy = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
Call this function to test if the TWI_ISR is busy transmitting.
|
||||||
|
****************************************************************************/
|
||||||
|
unsigned char TWI_Transceiver_Busy(void)
|
||||||
|
{
|
||||||
|
return TWI_busy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
Call this function to fetch the state information of the previous operation. The function will hold execution (loop)
|
||||||
|
until the TWI_ISR has completed with the previous operation. If there was an error, then the function
|
||||||
|
will return the TWI State code.
|
||||||
|
****************************************************************************/
|
||||||
|
unsigned char TWI_Get_State_Info(void)
|
||||||
|
{
|
||||||
|
while (TWI_Transceiver_Busy())
|
||||||
|
{
|
||||||
|
} // Wait until TWI has completed the transmission.
|
||||||
|
return (TWI_state); // Return error state.
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
Call this function to send a prepared message, or start the Transceiver for reception. Include
|
||||||
|
a pointer to the data to be sent if a SLA+W is received. The data will be copied to the TWI buffer.
|
||||||
|
Also include how many bytes that should be sent. Note that unlike the similar Master function, the
|
||||||
|
Address byte is not included in the message buffers.
|
||||||
|
The function will hold execution (loop) until the TWI_ISR has completed with the previous operation,
|
||||||
|
then initialize the next operation and return.
|
||||||
|
****************************************************************************/
|
||||||
|
void TWI_Start_Transceiver_With_Data(unsigned char *msg, unsigned char msgSize)
|
||||||
|
{
|
||||||
|
unsigned char temp;
|
||||||
|
|
||||||
|
while (TWI_Transceiver_Busy())
|
||||||
|
{
|
||||||
|
} // Wait until TWI is ready for next transmission.
|
||||||
|
|
||||||
|
TWI_msgSize = msgSize; // Number of data to transmit.
|
||||||
|
for (temp = 0; temp < msgSize; temp++) // Copy data that may be transmitted if the TWI Master requests data.
|
||||||
|
{
|
||||||
|
TWI_buf[temp] = msg[temp];
|
||||||
|
}
|
||||||
|
TWI_statusReg.all = 0;
|
||||||
|
TWI_state = TWI_NO_STATE;
|
||||||
|
TWCR = (1 << TWEN) | // TWI Interface enabled.
|
||||||
|
(1 << TWIE) | (1 << TWINT) | // Enable TWI Interrupt and clear the flag.
|
||||||
|
(1 << TWEA) | (0 << TWSTA) | (0 << TWSTO) | // Prepare to ACK next time the Slave is addressed.
|
||||||
|
(0 << TWWC); //
|
||||||
|
TWI_busy = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
Call this function to start the Transceiver without specifing new transmission data. Useful for restarting
|
||||||
|
a transmission, or just starting the transceiver for reception. The driver will reuse the data previously put
|
||||||
|
in the transceiver buffers. The function will hold execution (loop) until the TWI_ISR has completed with the
|
||||||
|
previous operation, then initialize the next operation and return.
|
||||||
|
****************************************************************************/
|
||||||
|
void TWI_Start_Transceiver(void)
|
||||||
|
{
|
||||||
|
while (TWI_Transceiver_Busy())
|
||||||
|
{
|
||||||
|
} // Wait until TWI is ready for next transmission.
|
||||||
|
TWI_statusReg.all = 0;
|
||||||
|
TWI_state = TWI_NO_STATE;
|
||||||
|
TWCR = (1 << TWEN) | // TWI Interface enabled.
|
||||||
|
(1 << TWIE) | (1 << TWINT) | // Enable TWI Interupt and clear the flag.
|
||||||
|
(1 << TWEA) | (0 << TWSTA) | (0 << TWSTO) | // Prepare to ACK next time the Slave is addressed.
|
||||||
|
(0 << TWWC); //
|
||||||
|
TWI_busy = 0;
|
||||||
|
}
|
||||||
|
/****************************************************************************
|
||||||
|
Call this function to read out the received data from the TWI transceiver buffer. I.e. first call
|
||||||
|
TWI_Start_Transceiver to get the TWI Transceiver to fetch data. Then Run this function to collect the
|
||||||
|
data when they have arrived. Include a pointer to where to place the data and the number of bytes
|
||||||
|
to fetch in the function call. The function will hold execution (loop) until the TWI_ISR has completed
|
||||||
|
with the previous operation, before reading out the data and returning.
|
||||||
|
If there was an error in the previous transmission the function will return the TWI State code.
|
||||||
|
****************************************************************************/
|
||||||
|
unsigned char TWI_Get_Data_From_Transceiver(unsigned char *msg, unsigned char msgSize)
|
||||||
|
{
|
||||||
|
unsigned char i;
|
||||||
|
|
||||||
|
while (TWI_Transceiver_Busy())
|
||||||
|
{
|
||||||
|
} // Wait until TWI is ready for next transmission.
|
||||||
|
|
||||||
|
if (TWI_statusReg.lastTransOK) // Last transmission completed successfully.
|
||||||
|
{
|
||||||
|
for (i = 0; i < msgSize; i++) // Copy data from Transceiver buffer.
|
||||||
|
{
|
||||||
|
msg[i] = TWI_buf[i];
|
||||||
|
}
|
||||||
|
TWI_statusReg.RxDataInBuf = FALSE; // Slave Receive data has been read from buffer.
|
||||||
|
}
|
||||||
|
return (TWI_statusReg.lastTransOK);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ********** Interrupt Handlers ********** //
|
||||||
|
/****************************************************************************
|
||||||
|
This function is the Interrupt Service Routine (ISR), and called when the TWI interrupt is triggered;
|
||||||
|
that is whenever a TWI event has occurred. This function should not be called directly from the main
|
||||||
|
application.
|
||||||
|
****************************************************************************/
|
||||||
|
ISR(TWI_vect)
|
||||||
|
{
|
||||||
|
static unsigned char TWI_bufPtr;
|
||||||
|
|
||||||
|
switch (TWSR)
|
||||||
|
{
|
||||||
|
case TWI_STX_ADR_ACK: // Own SLA+R has been received; ACK has been returned
|
||||||
|
// case TWI_STX_ADR_ACK_M_ARB_LOST: // Arbitration lost in SLA+R/W as Master; own SLA+R has been received; ACK has been returned
|
||||||
|
TWI_bufPtr = 0; // Set buffer pointer to first data location
|
||||||
|
case TWI_STX_DATA_ACK: // Data byte in TWDR has been transmitted; ACK has been received
|
||||||
|
TWDR = TWI_buf[TWI_bufPtr++];
|
||||||
|
TWCR = (1 << TWEN) | // TWI Interface enabled
|
||||||
|
(1 << TWIE) | (1 << TWINT) | // Enable TWI Interupt and clear the flag to send byte
|
||||||
|
(1 << TWEA) | (0 << TWSTA) | (0 << TWSTO) | //
|
||||||
|
(0 << TWWC); //
|
||||||
|
TWI_busy = 1;
|
||||||
|
break;
|
||||||
|
case TWI_STX_DATA_NACK: // Data byte in TWDR has been transmitted; NACK has been received.
|
||||||
|
// I.e. this could be the end of the transmission.
|
||||||
|
if (TWI_bufPtr == TWI_msgSize) // Have we transceived all expected data?
|
||||||
|
{
|
||||||
|
TWI_statusReg.lastTransOK = TRUE; // Set status bits to completed successfully.
|
||||||
|
}
|
||||||
|
else // Master has sent a NACK before all data where sent.
|
||||||
|
{
|
||||||
|
TWI_state = TWSR; // Store TWI State as errormessage.
|
||||||
|
}
|
||||||
|
|
||||||
|
TWCR = (1 << TWEN) | // Enable TWI-interface and release TWI pins
|
||||||
|
(1 << TWIE) | (1 << TWINT) | // Keep interrupt enabled and clear the flag
|
||||||
|
(1 << TWEA) | (0 << TWSTA) | (0 << TWSTO) | // Answer on next address match
|
||||||
|
(0 << TWWC); //
|
||||||
|
|
||||||
|
TWI_busy = 0; // Transmit is finished, we are not busy anymore
|
||||||
|
break;
|
||||||
|
case TWI_SRX_GEN_ACK: // General call address has been received; ACK has been returned
|
||||||
|
// case TWI_SRX_GEN_ACK_M_ARB_LOST: // Arbitration lost in SLA+R/W as Master; General call address has been received; ACK has been returned
|
||||||
|
TWI_statusReg.genAddressCall = TRUE;
|
||||||
|
case TWI_SRX_ADR_ACK: // Own SLA+W has been received ACK has been returned
|
||||||
|
// case TWI_SRX_ADR_ACK_M_ARB_LOST: // Arbitration lost in SLA+R/W as Master; own SLA+W has been received; ACK has been returned
|
||||||
|
// Dont need to clear TWI_S_statusRegister.generalAddressCall due to that it is the default state.
|
||||||
|
TWI_statusReg.RxDataInBuf = TRUE;
|
||||||
|
TWI_bufPtr = 0; // Set buffer pointer to first data location
|
||||||
|
|
||||||
|
// Reset the TWI Interupt to wait for a new event.
|
||||||
|
TWCR = (1 << TWEN) | // TWI Interface enabled
|
||||||
|
(1 << TWIE) | (1 << TWINT) | // Enable TWI Interupt and clear the flag to send byte
|
||||||
|
(1 << TWEA) | (0 << TWSTA) | (0 << TWSTO) | // Expect ACK on this transmission
|
||||||
|
(0 << TWWC);
|
||||||
|
TWI_busy = 1;
|
||||||
|
|
||||||
|
break;
|
||||||
|
case TWI_SRX_ADR_DATA_ACK: // Previously addressed with own SLA+W; data has been received; ACK has been returned
|
||||||
|
case TWI_SRX_GEN_DATA_ACK: // Previously addressed with general call; data has been received; ACK has been returned
|
||||||
|
TWI_buf[TWI_bufPtr++] = TWDR;
|
||||||
|
TWI_statusReg.lastTransOK = TRUE; // Set flag transmission successfull.
|
||||||
|
// Reset the TWI Interupt to wait for a new event.
|
||||||
|
TWCR = (1 << TWEN) | // TWI Interface enabled
|
||||||
|
(1 << TWIE) | (1 << TWINT) | // Enable TWI Interupt and clear the flag to send byte
|
||||||
|
(1 << TWEA) | (0 << TWSTA) | (0 << TWSTO) | // Send ACK after next reception
|
||||||
|
(0 << TWWC); //
|
||||||
|
TWI_busy = 1;
|
||||||
|
break;
|
||||||
|
case TWI_SRX_STOP_RESTART: // A STOP condition or repeated START condition has been received while still addressed as Slave
|
||||||
|
// Enter not addressed mode and listen to address match
|
||||||
|
TWCR = (1 << TWEN) | // Enable TWI-interface and release TWI pins
|
||||||
|
(1 << TWIE) | (1 << TWINT) | // Enable interrupt and clear the flag
|
||||||
|
(1 << TWEA) | (0 << TWSTA) | (0 << TWSTO) | // Wait for new address match
|
||||||
|
(0 << TWWC); //
|
||||||
|
|
||||||
|
TWI_busy = 0; // We are waiting for a new address match, so we are not busy
|
||||||
|
|
||||||
|
break;
|
||||||
|
case TWI_SRX_ADR_DATA_NACK: // Previously addressed with own SLA+W; data has been received; NOT ACK has been returned
|
||||||
|
case TWI_SRX_GEN_DATA_NACK: // Previously addressed with general call; data has been received; NOT ACK has been returned
|
||||||
|
case TWI_STX_DATA_ACK_LAST_BYTE: // Last data byte in TWDR has been transmitted (TWEA = �0�); ACK has been received
|
||||||
|
// case TWI_NO_STATE // No relevant state information available; TWINT = �0�
|
||||||
|
case TWI_BUS_ERROR: // Bus error due to an illegal START or STOP condition
|
||||||
|
TWI_state = TWSR; //Store TWI State as errormessage, operation also clears noErrors bit
|
||||||
|
TWCR = (1 << TWSTO) | (1 << TWINT); //Recover from TWI_BUS_ERROR, this will release the SDA and SCL pins thus enabling other devices to use the bus
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
TWI_state = TWSR; // Store TWI State as errormessage, operation also clears the Success bit.
|
||||||
|
TWCR = (1 << TWEN) | // Enable TWI-interface and release TWI pins
|
||||||
|
(1 << TWIE) | (1 << TWINT) | // Keep interrupt enabled and clear the flag
|
||||||
|
(1 << TWEA) | (0 << TWSTA) | (0 << TWSTO) | // Acknowledge on any new requests.
|
||||||
|
(0 << TWWC); //
|
||||||
|
|
||||||
|
TWI_busy = 0; // Unknown status, so we wait for a new address match that might be something we can handle
|
||||||
|
}
|
||||||
|
}
|
||||||
Executable
+124
@@ -0,0 +1,124 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
*
|
||||||
|
* Atmel Corporation
|
||||||
|
*
|
||||||
|
* File : TWI_Slave.h
|
||||||
|
* Compiler : IAR EWAAVR 2.28a/3.10c
|
||||||
|
* Revision : $Revision: 2475 $
|
||||||
|
* Date : $Date: 2007-09-20 12:00:43 +0200 (to, 20 sep 2007) $
|
||||||
|
* Updated by : $Author: mlarsson $
|
||||||
|
*
|
||||||
|
* Support mail : avr@atmel.com
|
||||||
|
*
|
||||||
|
* Supported devices : All devices with a TWI module can be used.
|
||||||
|
* The example is written for the ATmega16
|
||||||
|
*
|
||||||
|
* AppNote : AVR311 - TWI Slave Implementation
|
||||||
|
*
|
||||||
|
* Description : Header file for TWI_slave.c
|
||||||
|
* Include this file in the application.
|
||||||
|
*
|
||||||
|
****************************************************************************/
|
||||||
|
/*! \page MISRA
|
||||||
|
*
|
||||||
|
* General disabling of MISRA rules:
|
||||||
|
* * (MISRA C rule 1) compiler is configured to allow extensions
|
||||||
|
* * (MISRA C rule 111) bit fields shall only be defined to be of type unsigned int or signed int
|
||||||
|
* * (MISRA C rule 37) bitwise operations shall not be performed on signed integer types
|
||||||
|
* As it does not work well with 8bit architecture and/or IAR
|
||||||
|
|
||||||
|
* Other disabled MISRA rules
|
||||||
|
* * (MISRA C rule 109) use of union - overlapping storage shall not be used
|
||||||
|
* * (MISRA C rule 61) every non-empty case clause in a switch statement shall be terminated with a break statement
|
||||||
|
*/
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
TWI Status/Control register definitions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef TWI_BUFFER_SIZE
|
||||||
|
#define TWI_BUFFER_SIZE 8
|
||||||
|
#endif // Reserves memory for the drivers transceiver buffer. \
|
||||||
|
// Set this to the largest message size that will be sent including address byte.
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
Global definitions
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
union TWI_statusReg_t // Status byte holding flags.
|
||||||
|
{
|
||||||
|
unsigned char all;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
unsigned char lastTransOK : 1;
|
||||||
|
unsigned char RxDataInBuf : 1;
|
||||||
|
unsigned char genAddressCall : 1; // TRUE = General call, FALSE = TWI Address;
|
||||||
|
unsigned char unusedBits : 5;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
extern union TWI_statusReg_t TWI_statusReg;
|
||||||
|
|
||||||
|
static unsigned char dont_sleep = 0;
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
Function definitions
|
||||||
|
****************************************************************************/
|
||||||
|
void TWI_Slave_Initialise(unsigned char);
|
||||||
|
unsigned char TWI_Transceiver_Busy(void);
|
||||||
|
unsigned char TWI_Get_State_Info(void);
|
||||||
|
void TWI_Start_Transceiver_With_Data(unsigned char *, unsigned char);
|
||||||
|
void TWI_Start_Transceiver(void);
|
||||||
|
unsigned char TWI_Get_Data_From_Transceiver(unsigned char *, unsigned char);
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
Bit and byte definitions
|
||||||
|
****************************************************************************/
|
||||||
|
#define TWI_READ_BIT 0 // Bit position for R/W bit in "address byte".
|
||||||
|
#define TWI_ADR_BITS 1 // Bit position for LSB of the slave address bits in the init byte.
|
||||||
|
#define TWI_GEN_BIT 0 // Bit position for LSB of the general call bit in the init byte.
|
||||||
|
|
||||||
|
#define TRUE 1
|
||||||
|
#define FALSE 0
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
TWI State codes
|
||||||
|
****************************************************************************/
|
||||||
|
// General TWI Master status codes
|
||||||
|
#define TWI_START 0x08 // START has been transmitted
|
||||||
|
#define TWI_REP_START 0x10 // Repeated START has been transmitted
|
||||||
|
#define TWI_ARB_LOST 0x38 // Arbitration lost
|
||||||
|
|
||||||
|
// TWI Master Transmitter status codes
|
||||||
|
#define TWI_MTX_ADR_ACK 0x18 // SLA+W has been transmitted and ACK received
|
||||||
|
#define TWI_MTX_ADR_NACK 0x20 // SLA+W has been transmitted and NACK received
|
||||||
|
#define TWI_MTX_DATA_ACK 0x28 // Data byte has been transmitted and ACK received
|
||||||
|
#define TWI_MTX_DATA_NACK 0x30 // Data byte has been transmitted and NACK received
|
||||||
|
|
||||||
|
// TWI Master Receiver status codes
|
||||||
|
#define TWI_MRX_ADR_ACK 0x40 // SLA+R has been transmitted and ACK received
|
||||||
|
#define TWI_MRX_ADR_NACK 0x48 // SLA+R has been transmitted and NACK received
|
||||||
|
#define TWI_MRX_DATA_ACK 0x50 // Data byte has been received and ACK transmitted
|
||||||
|
#define TWI_MRX_DATA_NACK 0x58 // Data byte has been received and NACK transmitted
|
||||||
|
|
||||||
|
// TWI Slave Transmitter status codes
|
||||||
|
#define TWI_STX_ADR_ACK 0xA8 // Own SLA+R has been received; ACK has been returned
|
||||||
|
#define TWI_STX_ADR_ACK_M_ARB_LOST 0xB0 // Arbitration lost in SLA+R/W as Master; own SLA+R has been received; ACK has been returned
|
||||||
|
#define TWI_STX_DATA_ACK 0xB8 // Data byte in TWDR has been transmitted; ACK has been received
|
||||||
|
#define TWI_STX_DATA_NACK 0xC0 // Data byte in TWDR has been transmitted; NOT ACK has been received
|
||||||
|
#define TWI_STX_DATA_ACK_LAST_BYTE 0xC8 // Last data byte in TWDR has been transmitted (TWEA = �0�); ACK has been received
|
||||||
|
|
||||||
|
// TWI Slave Receiver status codes
|
||||||
|
#define TWI_SRX_ADR_ACK 0x60 // Own SLA+W has been received ACK has been returned
|
||||||
|
#define TWI_SRX_ADR_ACK_M_ARB_LOST 0x68 // Arbitration lost in SLA+R/W as Master; own SLA+W has been received; ACK has been returned
|
||||||
|
#define TWI_SRX_GEN_ACK 0x70 // General call address has been received; ACK has been returned
|
||||||
|
#define TWI_SRX_GEN_ACK_M_ARB_LOST 0x78 // Arbitration lost in SLA+R/W as Master; General call address has been received; ACK has been returned
|
||||||
|
#define TWI_SRX_ADR_DATA_ACK 0x80 // Previously addressed with own SLA+W; data has been received; ACK has been returned
|
||||||
|
#define TWI_SRX_ADR_DATA_NACK 0x88 // Previously addressed with own SLA+W; data has been received; NOT ACK has been returned
|
||||||
|
#define TWI_SRX_GEN_DATA_ACK 0x90 // Previously addressed with general call; data has been received; ACK has been returned
|
||||||
|
#define TWI_SRX_GEN_DATA_NACK 0x98 // Previously addressed with general call; data has been received; NOT ACK has been returned
|
||||||
|
#define TWI_SRX_STOP_RESTART 0xA0 // A STOP condition or repeated START condition has been received while still addressed as Slave
|
||||||
|
|
||||||
|
// TWI Miscellaneous status codes
|
||||||
|
#define TWI_NO_STATE 0xF8 // No relevant state information available; TWINT = �0�
|
||||||
|
#define TWI_BUS_ERROR 0x00 // Bus error due to an illegal START or STOP condition
|
||||||
@@ -0,0 +1,184 @@
|
|||||||
|
/*
|
||||||
|
* light weight WS2812 lib V2.0b
|
||||||
|
*
|
||||||
|
* Controls WS2811/WS2812/WS2812B RGB-LEDs
|
||||||
|
* Author: Tim (cpldcpu@gmail.com)
|
||||||
|
*
|
||||||
|
* Jan 18th, 2014 v2.0b Initial Version
|
||||||
|
* Nov 29th, 2015 v2.3 Added SK6812RGBW support
|
||||||
|
*
|
||||||
|
* License: GNU GPL v2+ (see License.txt)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "light_ws2812.h"
|
||||||
|
#include <avr/interrupt.h>
|
||||||
|
#include <avr/io.h>
|
||||||
|
|
||||||
|
#define F_CPU 16000000UL // 16Mhz
|
||||||
|
|
||||||
|
#include <util/delay.h>
|
||||||
|
|
||||||
|
// Setleds for standard RGB
|
||||||
|
void inline ws2812_setleds(struct cRGB *ledarray, uint16_t leds)
|
||||||
|
{
|
||||||
|
ws2812_setleds_pin(ledarray,leds, _BV(ws2812_pin));
|
||||||
|
}
|
||||||
|
|
||||||
|
void inline ws2812_setleds_pin(struct cRGB *ledarray, uint16_t leds, uint8_t pinmask)
|
||||||
|
{
|
||||||
|
ws2812_sendarray_mask((uint8_t*)ledarray,leds+leds+leds,pinmask);
|
||||||
|
_delay_us(ws2812_resettime);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setleds for SK6812RGBW
|
||||||
|
void inline ws2812_setleds_rgbw(struct cRGBW *ledarray, uint16_t leds)
|
||||||
|
{
|
||||||
|
ws2812_sendarray_mask((uint8_t*)ledarray,leds<<2,_BV(ws2812_pin));
|
||||||
|
_delay_us(ws2812_resettime);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ws2812_sendarray(uint8_t *data,uint16_t datlen)
|
||||||
|
{
|
||||||
|
ws2812_sendarray_mask(data,datlen,_BV(ws2812_pin));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
This routine writes an array of bytes with RGB values to the Dataout pin
|
||||||
|
using the fast 800kHz clockless WS2811/2812 protocol.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Timing in ns
|
||||||
|
#define w_zeropulse 350
|
||||||
|
#define w_onepulse 900
|
||||||
|
#define w_totalperiod 1250
|
||||||
|
|
||||||
|
// Fixed cycles used by the inner loop
|
||||||
|
#define w_fixedlow 2
|
||||||
|
#define w_fixedhigh 4
|
||||||
|
#define w_fixedtotal 8
|
||||||
|
|
||||||
|
// Insert NOPs to match the timing, if possible
|
||||||
|
#define w_zerocycles (((F_CPU/1000)*w_zeropulse )/1000000)
|
||||||
|
#define w_onecycles (((F_CPU/1000)*w_onepulse +500000)/1000000)
|
||||||
|
#define w_totalcycles (((F_CPU/1000)*w_totalperiod +500000)/1000000)
|
||||||
|
|
||||||
|
// w1 - nops between rising edge and falling edge - low
|
||||||
|
#define w1 (w_zerocycles-w_fixedlow)
|
||||||
|
// w2 nops between fe low and fe high
|
||||||
|
#define w2 (w_onecycles-w_fixedhigh-w1)
|
||||||
|
// w3 nops to complete loop
|
||||||
|
#define w3 (w_totalcycles-w_fixedtotal-w1-w2)
|
||||||
|
|
||||||
|
#if w1>0
|
||||||
|
#define w1_nops w1
|
||||||
|
#else
|
||||||
|
#define w1_nops 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// The only critical timing parameter is the minimum pulse length of the "0"
|
||||||
|
// Warn or throw error if this timing can not be met with current F_CPU settings.
|
||||||
|
#define w_lowtime ((w1_nops+w_fixedlow)*1000000)/(F_CPU/1000)
|
||||||
|
#if w_lowtime>550
|
||||||
|
#error "Light_ws2812: Sorry, the clock speed is too low. Did you set F_CPU correctly?"
|
||||||
|
#elif w_lowtime>450
|
||||||
|
#warning "Light_ws2812: The timing is critical and may only work on WS2812B, not on WS2812(S)."
|
||||||
|
#warning "Please consider a higher clockspeed, if possible"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if w2>0
|
||||||
|
#define w2_nops w2
|
||||||
|
#else
|
||||||
|
#define w2_nops 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if w3>0
|
||||||
|
#define w3_nops w3
|
||||||
|
#else
|
||||||
|
#define w3_nops 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define w_nop1 "nop \n\t"
|
||||||
|
#define w_nop2 "rjmp .+0 \n\t"
|
||||||
|
#define w_nop4 w_nop2 w_nop2
|
||||||
|
#define w_nop8 w_nop4 w_nop4
|
||||||
|
#define w_nop16 w_nop8 w_nop8
|
||||||
|
|
||||||
|
void inline ws2812_sendarray_mask(uint8_t *data,uint16_t datlen,uint8_t maskhi)
|
||||||
|
{
|
||||||
|
uint8_t curbyte,ctr,masklo;
|
||||||
|
uint8_t sreg_prev;
|
||||||
|
|
||||||
|
ws2812_DDRREG |= maskhi; // Enable output
|
||||||
|
|
||||||
|
masklo =~maskhi&ws2812_PORTREG;
|
||||||
|
maskhi |= ws2812_PORTREG;
|
||||||
|
|
||||||
|
sreg_prev=SREG;
|
||||||
|
cli();
|
||||||
|
|
||||||
|
while (datlen--) {
|
||||||
|
curbyte=*data++;
|
||||||
|
|
||||||
|
asm volatile(
|
||||||
|
" ldi %0,8 \n\t"
|
||||||
|
"loop%=: \n\t"
|
||||||
|
" out %2,%3 \n\t" // '1' [01] '0' [01] - re
|
||||||
|
#if (w1_nops&1)
|
||||||
|
w_nop1
|
||||||
|
#endif
|
||||||
|
#if (w1_nops&2)
|
||||||
|
w_nop2
|
||||||
|
#endif
|
||||||
|
#if (w1_nops&4)
|
||||||
|
w_nop4
|
||||||
|
#endif
|
||||||
|
#if (w1_nops&8)
|
||||||
|
w_nop8
|
||||||
|
#endif
|
||||||
|
#if (w1_nops&16)
|
||||||
|
w_nop16
|
||||||
|
#endif
|
||||||
|
" sbrs %1,7 \n\t" // '1' [03] '0' [02]
|
||||||
|
" out %2,%4 \n\t" // '1' [--] '0' [03] - fe-low
|
||||||
|
" lsl %1 \n\t" // '1' [04] '0' [04]
|
||||||
|
#if (w2_nops&1)
|
||||||
|
w_nop1
|
||||||
|
#endif
|
||||||
|
#if (w2_nops&2)
|
||||||
|
w_nop2
|
||||||
|
#endif
|
||||||
|
#if (w2_nops&4)
|
||||||
|
w_nop4
|
||||||
|
#endif
|
||||||
|
#if (w2_nops&8)
|
||||||
|
w_nop8
|
||||||
|
#endif
|
||||||
|
#if (w2_nops&16)
|
||||||
|
w_nop16
|
||||||
|
#endif
|
||||||
|
" out %2,%4 \n\t" // '1' [+1] '0' [+1] - fe-high
|
||||||
|
#if (w3_nops&1)
|
||||||
|
w_nop1
|
||||||
|
#endif
|
||||||
|
#if (w3_nops&2)
|
||||||
|
w_nop2
|
||||||
|
#endif
|
||||||
|
#if (w3_nops&4)
|
||||||
|
w_nop4
|
||||||
|
#endif
|
||||||
|
#if (w3_nops&8)
|
||||||
|
w_nop8
|
||||||
|
#endif
|
||||||
|
#if (w3_nops&16)
|
||||||
|
w_nop16
|
||||||
|
#endif
|
||||||
|
|
||||||
|
" dec %0 \n\t" // '1' [+2] '0' [+2]
|
||||||
|
" brne loop%=\n\t" // '1' [+3] '0' [+4]
|
||||||
|
: "=&d" (ctr)
|
||||||
|
: "r" (curbyte), "I" (_SFR_IO_ADDR(ws2812_PORTREG)), "r" (maskhi), "r" (masklo)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
SREG=sreg_prev;
|
||||||
|
}
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
* light weight WS2812 lib include
|
||||||
|
*
|
||||||
|
* Version 2.3 - Nev 29th 2015
|
||||||
|
* Author: Tim (cpldcpu@gmail.com)
|
||||||
|
*
|
||||||
|
* Please do not change this file! All configuration is handled in "ws2812_config.h"
|
||||||
|
*
|
||||||
|
* License: GNU GPL v2+ (see License.txt)
|
||||||
|
+
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LIGHT_WS2812_H_
|
||||||
|
#define LIGHT_WS2812_H_
|
||||||
|
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include <avr/interrupt.h>
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////
|
||||||
|
// Define Reset time in µs.
|
||||||
|
//
|
||||||
|
// This is the time the library spends waiting after writing the data.
|
||||||
|
//
|
||||||
|
// WS2813 needs 300 µs reset time
|
||||||
|
// WS2812 and clones only need 50 µs
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////
|
||||||
|
#if !defined(ws2812_resettime)
|
||||||
|
#define ws2812_resettime 300
|
||||||
|
#endif
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////
|
||||||
|
// Define I/O pin
|
||||||
|
///////////////////////////////////////////////////////////////////////
|
||||||
|
#if !defined(ws2812_port)
|
||||||
|
#define ws2812_port B // Data port
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(ws2812_pin)
|
||||||
|
#define ws2812_pin 2 // Data out pin
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Structure of the LED array
|
||||||
|
*
|
||||||
|
* cRGB: RGB for WS2812S/B/C/D, SK6812, SK6812Mini, SK6812WWA, APA104, APA106
|
||||||
|
* cRGBW: RGBW for SK6812RGBW
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct cRGB { uint8_t g; uint8_t r; uint8_t b; };
|
||||||
|
struct cRGBW { uint8_t g; uint8_t r; uint8_t b; uint8_t w;};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* User Interface
|
||||||
|
*
|
||||||
|
* Input:
|
||||||
|
* ledarray: An array of GRB data describing the LED colors
|
||||||
|
* number_of_leds: The number of LEDs to write
|
||||||
|
* pinmask (optional): Bitmask describing the output bin. e.g. _BV(PB0)
|
||||||
|
*
|
||||||
|
* The functions will perform the following actions:
|
||||||
|
* - Set the data-out pin as output
|
||||||
|
* - Send out the LED data
|
||||||
|
* - Wait 50µs to reset the LEDs
|
||||||
|
*/
|
||||||
|
|
||||||
|
void ws2812_setleds (struct cRGB *ledarray, uint16_t number_of_leds);
|
||||||
|
void ws2812_setleds_pin (struct cRGB *ledarray, uint16_t number_of_leds,uint8_t pinmask);
|
||||||
|
void ws2812_setleds_rgbw(struct cRGBW *ledarray, uint16_t number_of_leds);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Old interface / Internal functions
|
||||||
|
*
|
||||||
|
* The functions take a byte-array and send to the data output as WS2812 bitstream.
|
||||||
|
* The length is the number of bytes to send - three per LED.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void ws2812_sendarray (uint8_t *array,uint16_t length);
|
||||||
|
void ws2812_sendarray_mask(uint8_t *array,uint16_t length, uint8_t pinmask);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Internal defines
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CONCAT(a, b) a ## b
|
||||||
|
#define CONCAT_EXP(a, b) CONCAT(a, b)
|
||||||
|
|
||||||
|
#define ws2812_PORTREG CONCAT_EXP(PORT,ws2812_port)
|
||||||
|
#define ws2812_DDRREG CONCAT_EXP(DDR,ws2812_port)
|
||||||
|
|
||||||
|
#endif /* LIGHT_WS2812_H_ */
|
||||||
+40
@@ -0,0 +1,40 @@
|
|||||||
|
#define F_CPU 16000000UL // 16Mhz
|
||||||
|
#define I2C_ADDR 0b1000010 // 0x84h
|
||||||
|
|
||||||
|
#define ws2812_resettime 300
|
||||||
|
#define ws2812_port B
|
||||||
|
#define ws2812_pin 2
|
||||||
|
|
||||||
|
#define RGBW_COUNT 15
|
||||||
|
#define TWI_BUFFER_SIZE RGBW_COUNT * 4 // 15 RGBW leds, 4 byte each
|
||||||
|
|
||||||
|
#include <util/delay.h>
|
||||||
|
#include <avr/interrupt.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "TWI_slave.h"
|
||||||
|
#include "light_ws2812.h"
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
TWI_Slave_Initialise(I2C_ADDR << 1);
|
||||||
|
TWI_Start_Transceiver();
|
||||||
|
DDRB |= _BV(ws2812_pin);
|
||||||
|
sei();
|
||||||
|
|
||||||
|
uint8_t rxMessage[TWI_BUFFER_SIZE];
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
if (!TWI_Transceiver_Busy() && TWI_statusReg.RxDataInBuf)
|
||||||
|
{
|
||||||
|
TWI_Get_Data_From_Transceiver(rxMessage, TWI_BUFFER_SIZE);
|
||||||
|
ws2812_sendarray((uint8_t *)rxMessage, TWI_BUFFER_SIZE);
|
||||||
|
TWI_Start_Transceiver();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TIFR1 & _BV(OCF1A))
|
||||||
|
{
|
||||||
|
TIFR1 = _BV(OCF1A);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user