From 217ddb1e32dcb4cde11ecca88418be428895f2dc Mon Sep 17 00:00:00 2001 From: Wolfgang Draxinger Date: Sun, 22 Dec 2013 16:44:10 +0100 Subject: Makefile separator errors fixed --- Makefile | 92 ++++++++++++ avr_compiler.h | 154 ++++++++++++++++++++ edid_injector.c | 132 +++++++++++++++++ eeprom_driver.c | 330 +++++++++++++++++++++++++++++++++++++++++++ eeprom_driver.h | 142 +++++++++++++++++++ twi_master_driver.c | 399 ++++++++++++++++++++++++++++++++++++++++++++++++++++ twi_master_driver.h | 147 +++++++++++++++++++ twi_slave_driver.c | 321 ++++++++++++++++++++++++++++++++++++++++++ twi_slave_driver.h | 135 ++++++++++++++++++ 9 files changed, 1852 insertions(+) create mode 100644 Makefile create mode 100644 avr_compiler.h create mode 100644 edid_injector.c create mode 100644 eeprom_driver.c create mode 100644 eeprom_driver.h create mode 100644 twi_master_driver.c create mode 100644 twi_master_driver.h create mode 100644 twi_slave_driver.c create mode 100644 twi_slave_driver.h diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..fc74b31 --- /dev/null +++ b/Makefile @@ -0,0 +1,92 @@ +## Change these: +## HWREV: +## 0 -> initial revision +MMCU = atxmega16a4 +DEFINES = -DF_CPU=32000000 -DHWREV=0 + +# -b baudrate +AVRDUDE = avrdude -P usb -c jtag3pdi -p $(MMCU) + +#------------------------------------------------------------------------------- + +HEADERS = twi_master_driver.h twi_slave_driver.h eeprom_driver.h avr_compiler.h +SOURCES = twi_master_driver.c twi_slave_driver.c eeprom_driver.c edid_injector.c +OBJECTS = $(SOURCES:.c=.o) + +INCLUDES = -I. + +VPATH = . + +#------------------------------------------------------------------------------- +CC = avr-gcc +CFLAGS = -W -Wall -Os -std=gnu99 -Werror-implicit-function-declaration + +all: firmware.bin firmware.hex firmware-eeprom.bin + +run: all prg + +firmware.elf: $(OBJECTS) + $(CC) -s -mmcu=$(MMCU) $(OBJECTS) -o firmware.elf + +%.o: %.c $(HEADERS) + $(CC) $(INCLUDES) -mmcu=$(MMCU) $(CPPFLAGS) $(CFLAGS) $(DEFINES) -c $< + +# FUSEBYTE0: JTAG user ID (arbitrary) +# FUSEBYTE1: +# bits 7..4: Watchdog Window Timeout Period +# bits 3..0: Watchdog Timeout Period +# FUSEBYTE2: +# bit 6: BOOTRST +# 0: Reset vector = Boot loader reset +# 1: Reset vector = Application reset (address 0x0000) +# bit 5: TOSCSEL (32768 kHz osc pin position; usually 1) +# bits 1..0: BODPD[1:0]: (in power-down mode) +# 10 = BOD enabled continuously +# 11 = BOD disabled +# FUSEBYTE4: +# bit 4: RSTDISBL 0: disable reset +# bits 3..2: STARTUPTIME[1:0] 11/01/00: wait 0/4/64 cycles +# bit 1: WDLOCK 1: watchdog timer not locked +# bit 0: JTAGEN 1: JTAG disabled +# FUSEBYTE5: +# bits 5..4: BODACT[1:0] +# 10 = BOD enabled continuously +# 11 = BOD disabled +# bit 3: EESAVE 0: EEPROM is preserved during chip erase +# bits 2..0: BODLEVEL[2:0] +# 111: 1.6 011: 2.4 +# 110: 1.8 010: 2.6 +# 101: 2.0 001: 2.8 +# 100: 2.2 000: 3.0 +program_fuses: + $(AVRDUDE) \ + -Ufuse0:w:0xff:m -Ufuse1:w:0x66:m -Ufuse2:w:0xfe:m + -Ufuse5:w:0xeb:m -Ufuse4:w:0xff:m + +prg: firmware.hex + $(AVRDUDE) -Uflash:w:firmware.hex:i + +program_bootloader: + $(AVRDUDE) -e -Uflash:w:bootload.hex:i + +dump: firmware.elf + avr-objdump -D firmware.elf + +clean: + -rm -f firmware.bin firmware.elf firmware-eeprom.bin firmware.hex + -rm -f *.o + +firmware-eeprom.bin: firmware.elf + avr-objcopy -j .eeprom -O binary firmware.elf firmware-eeprom.bin + @ls -l firmware-eeprom.bin + +firmware.hex: firmware.elf + avr-objcopy -j .text -j .data -O ihex firmware.elf firmware.hex + +firmware.bin: firmware.elf + avr-objcopy -j .text -j .data -O binary firmware.elf firmware.bin + @ls -l firmware.bin + +asm: + $(CC) -W -Wall -O2 -mmcu=$(MMCU) -S main.c -o main.asm + diff --git a/avr_compiler.h b/avr_compiler.h new file mode 100644 index 0000000..5d1c738 --- /dev/null +++ b/avr_compiler.h @@ -0,0 +1,154 @@ +/* This file has been prepared for Doxygen automatic documentation generation.*/ +/*! \file ********************************************************************* + * + * \brief This file implements some macros that makes the IAR C-compiler and + * avr-gcc work with the same code base for the AVR architecture. + * + * \par Documentation + * For comprehensive code documentation, supported compilers, compiler + * settings and supported devices see readme.html + * + * \author + * Atmel Corporation: http://www.atmel.com \n + * Support email: avr@atmel.com + * + * $Revision: 613 $ + * $Date: 2006-04-07 14:40:07 +0200 (fr, 07 apr 2006) $ \n + * + * Copyright (c) 2008, Atmel Corporation All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of ATMEL may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY AND + * SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + ******************************************************************************/ + +#ifndef COMPILER_AVR_H +#define COMPILER_AVR_H + +#ifndef F_CPU +/*! \brief Define default CPU frequency, if this is not already defined. */ +#define F_CPU 2000000UL +#endif + +#include +#include +#include + +/*! \brief This macro will protect the following code from interrupts. */ +#define AVR_ENTER_CRITICAL_REGION( ) uint8_t volatile saved_sreg = SREG; \ + cli(); + +/*! \brief This macro must always be used in conjunction with AVR_ENTER_CRITICAL_REGION + * so the interrupts are enabled again. + */ +#define AVR_LEAVE_CRITICAL_REGION( ) SREG = saved_sreg; + +#if defined( __ICCAVR__ ) + +#include +#include +#include +#include + +#ifndef __HAS_ELPM__ +#define _MEMATTR __flash +#else /* __HAS_ELPM__ */ +#define _MEMATTR __farflash +#endif /* __HAS_ELPM__ */ + +/*! \brief Perform a delay of \c us microseconds. + * + * The macro F_CPU is supposed to be defined to a constant defining the CPU + * clock frequency (in Hertz). + * + * The maximal possible delay is 262.14 ms / F_CPU in MHz. + * + * \note For the IAR compiler, currently F_CPU must be a + * multiple of 1000000UL (1 MHz). + */ +#define delay_us( us ) ( __delay_cycles( ( F_CPU / 1000000UL ) * ( us ) ) ) + +/*! \brief Preprocessor magic. + * + * Some preprocessor magic to allow for a header file abstraction of + * interrupt service routine declarations for the IAR compiler. This + * requires the use of the C99 _Pragma() directive (rather than the + * old #pragma one that could not be used as a macro replacement), as + * well as two different levels of preprocessor concetanations in + * order to do both, assign the correct interrupt vector name, as well + * as construct a unique function name for the ISR. + * + * \note Do *NOT* try to reorder the macros below, as this will only + * work in the given order. + */ +#define PRAGMA(x) _Pragma( #x ) +#define ISR(vec) PRAGMA( vector=vec ) __interrupt void handler_##vec(void) +#define sei( ) (__enable_interrupt( )) +#define cli( ) (__disable_interrupt( )) + +/*! \brief Define the no operation macro. */ +#define nop( ) (__no_operation()) + +/*! \brief Define the watchdog reset macro. */ +#define watchdog_reset( ) (__watchdog_reset( )) + + +#define INLINE PRAGMA( inline=forced ) static + +#define FLASH_DECLARE(x) _MEMATTR x +#define FLASH_STRING(x) ((_MEMATTR const char *)(x)) +#define FLASH_STRING_T char const _MEMATTR * +#define FLASH_BYTE_ARRAY_T uint8_t const _MEMATTR * +#define PGM_READ_BYTE(x) *(x) +#define PGM_READ_WORD(x) *(x) + +#define SHORTENUM /**/ + +#elif defined( __GNUC__ ) + +#include +#include +#include +#include + +/*! \brief Define the delay_us macro for GCC. */ +#define delay_us( us ) (_delay_us( us )) + +#define INLINE static inline + +/*! \brief Define the no operation macro. */ +#define nop() do { __asm__ __volatile__ ("nop"); } while (0) + +#define MAIN_TASK_PROLOGUE int + + +#define MAIN_TASK_EPILOGUE() return -1; + +#define SHORTENUM __attribute__ ((packed)) + +#else +#error Compiler not supported. +#endif + +#endif + diff --git a/edid_injector.c b/edid_injector.c new file mode 100644 index 0000000..5a539e4 --- /dev/null +++ b/edid_injector.c @@ -0,0 +1,132 @@ +/* This file has been prepared for Doxygen automatic documentation generation.*/ +/*! \file ********************************************************************* + * + * \brief EDID Injector firmware + * + * \author + * Wolfgang 'datenwolf' Draxinger + * Support email: projects+edid_injector@datenwolf.net + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of ATMEL may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY AND + * SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ +#include "avr_compiler.h" +#include "twi_master_driver.h" +#include "twi_slave_driver.h" +#include "eeprom_driver.h" + +/*! AUDRATE 100kHz and Baudrate Register Settings */ +#define BAUDRATE 100000 +#define TWI_BAUDSETTING TWI_BAUD(F_CPU, BAUDRATE) + +/* TWIC is on the display side */ +TWI_t * const twiDisplay = &TWIC; +TWI_Master_t twimDisplay; /*!< TWI master module. Used for talking with display */ + +/* TWIE is on the host side */ +TWI_t * const twiHost = &TWIE; +TWI_Slave_t twimHost; /*!< TWI slave module. Used for talking with host */ + + +void TWIC_SlaveProcessData(void) +{ +} + +void edid_initHostTWI(void) +{ +} + +void edid_initDisplayTWI(void) +{ +} + +void edid_readFromDisplayToEEPROM(void) +{ + uint8_t buffer[128]; + memset(buffer, 0, sizeof(buffer); + +} + +int main(void) +{ + edid_initHostTWI(); + + edid_initDisplayTWI(); + + /* Initialize PORTE for output and PORTD for inverted input. */ + PORTE.DIRSET = 0xFF; + PORTD.DIRCLR = 0xFF; + PORTCFG.MPCMASK = 0xFF; + PORTD.PIN0CTRL |= PORT_INVEN_bm; +// PORTCFG.MPCMASK = 0xFF; +// PORTD.PIN0CTRL = (PORTD.PIN0CTRL & ~PORT_OPC_gm) | PORT_OPC_PULLUP_gc; + + // Enable internal pull-up on PC0, PC1.. Uncomment if you don't have external pullups +// PORTCFG.MPCMASK = 0x03; // Configure several PINxCTRL registers at the same time +// PORTC.PIN0CTRL = (PORTC.PIN0CTRL & ~PORT_OPC_gm) | PORT_OPC_PULLUP_gc; //Enable pull-up to get a defined level on the switches + + + + /* Initialize TWI master. */ + TWI_MasterInit(&twiMaster, + &TWIC, + TWI_MASTER_INTLVL_LO_gc, + TWI_BAUDSETTING); + + /* Initialize TWI slave. */ + TWI_SlaveInitializeDriver(&twiSlave, &TWIC, TWIC_SlaveProcessData); + TWI_SlaveInitializeModule(&twiSlave, + SLAVE_ADDRESS, + TWI_SLAVE_INTLVL_LO_gc); + + /* Enable LO interrupt level. */ + PMIC.CTRL |= PMIC_LOLVLEN_bm; + sei(); + + + #if 0 + TWI_MasterWriteRead(&twiMaster, + SLAVE_ADDRESS, + &sendBuffer[BufPos], + 1, + 1); + + + while (twiMaster.status != TWIM_STATUS_READY) { + /* Wait until transaction is complete. */ + } + #endif +} + +/*! TWIC Master Interrupt vector. */ +ISR(TWIC_TWIM_vect) +{ + TWI_MasterInterruptHandler(&twiMaster); +} + +/*! TWIC Slave Interrupt vector. */ +ISR(TWIC_TWIS_vect) +{ + TWI_SlaveInterruptHandler(&twiSlave); +} diff --git a/eeprom_driver.c b/eeprom_driver.c new file mode 100644 index 0000000..cc849a6 --- /dev/null +++ b/eeprom_driver.c @@ -0,0 +1,330 @@ +/* This file has been prepared for Doxygen automatic documentation generation.*/ +/*! \file ********************************************************************* + * + * \brief XMEGA EEPROM driver source file. + * + * This file contains the function implementations for the XMEGA EEPROM driver. + * + * The driver is not intended for size and/or speed critical code, since + * most functions are just a few lines of code, and the function call + * overhead would decrease code performance. The driver is intended for + * rapid prototyping and documentation purposes for getting started with + * the XMEGA EEPROM module. + * + * For size and/or speed critical code, it is recommended to copy the + * function contents directly into your application instead of making + * a function call. + * + * \par Application note: + * AVR1315: Accessing the XMEGA EEPROM + * + * \par Documentation + * For comprehensive code documentation, supported compilers, compiler + * settings and supported devices see readme.html + * + * \author + * Atmel Corporation: http://www.atmel.com \n + * Support email: avr@atmel.com + * + * $Revision: 1569 $ + * $Date: 2008-04-22 13:03:43 +0200 (ti, 22 apr 2008) $ \n + * + * Copyright (c) 2008, Atmel Corporation All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of ATMEL may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY AND + * SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +#include "eeprom_driver.h" + +/*! \brief Write one byte to EEPROM using IO mapping. + * + * This function writes one byte to EEPROM using IO-mapped access. + * If memory mapped EEPROM is enabled, this function will not work. + * This functiom will cancel all ongoing EEPROM page buffer loading + * operations, if any. + * + * \param pageAddr EEPROM Page address, between 0 and EEPROM_SIZE/EEPROM_PAGESIZE + * \param byteAddr EEPROM Byte address, between 0 and EEPROM_PAGESIZE. + * \param value Byte value to write to EEPROM. + */ +void EEPROM_WriteByte( uint8_t pageAddr, uint8_t byteAddr, uint8_t value ) +{ + /* Flush buffer to make sure no unintetional data is written and load + * the "Page Load" command into the command register. + */ + EEPROM_FlushBuffer(); + NVM.CMD = NVM_CMD_LOAD_EEPROM_BUFFER_gc; + + /* Calculate address */ + uint16_t address = (uint16_t)(pageAddr*EEPROM_PAGESIZE) + |(byteAddr & (EEPROM_PAGESIZE-1)); + + /* Set address to write to. */ + NVM.ADDR0 = address & 0xFF; + NVM.ADDR1 = (address >> 8) & 0x1F; + NVM.ADDR2 = 0x00; + + /* Load data to write, which triggers the loading of EEPROM page buffer. */ + NVM.DATA0 = value; + + /* Issue EEPROM Atomic Write (Erase&Write) command. Load command, write + * the protection signature and execute command. + */ + NVM.CMD = NVM_CMD_ERASE_WRITE_EEPROM_PAGE_gc; + NVM_EXEC(); +} + + +/*! \brief Read one byte from EEPROM using IO mapping. + * + * This function reads one byte from EEPROM using IO-mapped access. + * If memory mapped EEPROM is enabled, this function will not work. + * + * \param pageAddr EEPROM Page address, between 0 and EEPROM_SIZE/EEPROM_PAGESIZE + * \param byteAddr EEPROM Byte address, between 0 and EEPROM_PAGESIZE. + * + * \return Byte value read from EEPROM. + */ +uint8_t EEPROM_ReadByte( uint8_t pageAddr, uint8_t byteAddr ) +{ + /* Wait until NVM is not busy. */ + EEPROM_WaitForNVM(); + + /* Calculate address */ + uint16_t address = (uint16_t)(pageAddr*EEPROM_PAGESIZE) + |(byteAddr & (EEPROM_PAGESIZE-1)); + + /* Set address to read from. */ + NVM.ADDR0 = address & 0xFF; + NVM.ADDR1 = (address >> 8) & 0x1F; + NVM.ADDR2 = 0x00; + + /* Issue EEPROM Read command. */ + NVM.CMD = NVM_CMD_READ_EEPROM_gc; + NVM_EXEC(); + + return NVM.DATA0; +} + + +/*! \brief Wait for any NVM access to finish, including EEPROM. + * + * This function is blcoking and waits for any NVM access to finish, + * including EEPROM. Use this function before any EEPROM accesses, + * if you are not certain that any previous operations are finished yet, + * like an EEPROM write. + */ +void EEPROM_WaitForNVM( void ) +{ + do { + /* Block execution while waiting for the NVM to be ready. */ + } while ((NVM.STATUS & NVM_NVMBUSY_bm) == NVM_NVMBUSY_bm); +} + + +/*! \brief Flush temporary EEPROM page buffer. + * + * This function flushes the EEPROM page buffers. This function will cancel + * any ongoing EEPROM page buffer loading operations, if any. + * This function also works for memory mapped EEPROM access. + * + * \note The EEPROM write operations will automatically flush the buffer for you. + */ +void EEPROM_FlushBuffer( void ) +{ + /* Wait until NVM is not busy. */ + EEPROM_WaitForNVM(); + + /* Flush EEPROM page buffer if necessary. */ + if ((NVM.STATUS & NVM_EELOAD_bm) != 0) { + NVM.CMD = NVM_CMD_ERASE_EEPROM_BUFFER_gc; + NVM_EXEC(); + } +} + + +/*! \brief Load single byte into temporary page buffer. + * + * This function loads one byte into the temporary EEPROM page buffers. + * If memory mapped EEPROM is enabled, this function will not work. + * Make sure that the buffer is flushed before starting to load bytes. + * Also, if multiple bytes are loaded into the same location, they will + * be ANDed together, thus 0x55 and 0xAA will result in 0x00 in the buffer. + * + * \note Only one page buffer exist, thus only one page can be loaded with + * data and programmed into one page. If data needs to be written to + * different pages, the loading and writing needs to be repeated. + * + * \param byteAddr EEPROM Byte address, between 0 and EEPROM_PAGESIZE. + * \param value Byte value to write to buffer. + */ +void EEPROM_LoadByte( uint8_t byteAddr, uint8_t value ) +{ + /* Wait until NVM is not busy and prepare NVM command.*/ + EEPROM_WaitForNVM(); + NVM.CMD = NVM_CMD_LOAD_EEPROM_BUFFER_gc; + + /* Set address. */ + NVM.ADDR0 = byteAddr & 0xFF; + NVM.ADDR1 = 0x00; + NVM.ADDR2 = 0x00; + + /* Set data, which triggers loading of EEPROM page buffer. */ + NVM.DATA0 = value; +} + + +/*! \brief Load entire page into temporary EEPROM page buffer. + * + * This function loads an entire EEPROM page from an SRAM buffer to + * the EEPROM page buffers. If memory mapped EEPROM is enabled, this + * function will not work. Make sure that the buffer is flushed before + * starting to load bytes. + * + * \note Only the lower part of the address is used to address the buffer. + * Therefore, no address parameter is needed. In the end, the data + * is written to the EEPROM page given by the address parameter to the + * EEPROM write page operation. + * + * \param values Pointer to SRAM buffer containing an entire page. + */ +void EEPROM_LoadPage( const uint8_t * values ) +{ + /* Wait until NVM is not busy. */ + EEPROM_WaitForNVM(); + NVM.CMD = NVM_CMD_LOAD_EEPROM_BUFFER_gc; + + /* Set address to zero, as only the lower bits matters. ADDR0 is + * maintained inside the loop below. + */ + NVM.ADDR1 = 0x00; + NVM.ADDR2 = 0x00; + + /* Load multible bytes into page buffer. */ + for (uint8_t i = 0; i < EEPROM_PAGESIZE; ++i) { + NVM.ADDR0 = i; + NVM.DATA0 = *values; + ++values; + } +} + +/*! \brief Write already loaded page into EEPROM. + * + * This function writes the contents of an already loaded EEPROM page + * buffer into EEPROM memory. + * + * As this is an atomic write, the page in EEPROM will be erased + * automatically before writing. Note that only the page buffer locations + * that have been loaded will be used when writing to EEPROM. Page buffer + * locations that have not been loaded will be left untouched in EEPROM. + * + * \param pageAddr EEPROM Page address, between 0 and EEPROM_SIZE/EEPROM_PAGESIZE + */ +void EEPROM_AtomicWritePage( uint8_t pageAddr ) +{ + /* Wait until NVM is not busy. */ + EEPROM_WaitForNVM(); + + /* Calculate page address */ + uint16_t address = (uint16_t)(pageAddr*EEPROM_PAGESIZE); + + /* Set address. */ + NVM.ADDR0 = address & 0xFF; + NVM.ADDR1 = (address >> 8) & 0x1F; + NVM.ADDR2 = 0x00; + + /* Issue EEPROM Atomic Write (Erase&Write) command. */ + NVM.CMD = NVM_CMD_ERASE_WRITE_EEPROM_PAGE_gc; + NVM_EXEC(); +} + + +/*! \brief Erase EEPROM page. + * + * This function erases one EEPROM page, so that every location reads 0xFF. + * + * \param pageAddr EEPROM Page address, between 0 and EEPROM_SIZE/EEPROM_PAGESIZE + */ +void EEPROM_ErasePage( uint8_t pageAddr ) +{ + /* Wait until NVM is not busy. */ + EEPROM_WaitForNVM(); + + /* Calculate page address */ + uint16_t address = (uint16_t)(pageAddr*EEPROM_PAGESIZE); + + /* Set address. */ + NVM.ADDR0 = address & 0xFF; + NVM.ADDR1 = (address >> 8) & 0x1F; + NVM.ADDR2 = 0x00; + + /* Issue EEPROM Erase command. */ + NVM.CMD = NVM_CMD_ERASE_EEPROM_PAGE_gc; + NVM_EXEC(); +} + + +/*! \brief Write (without erasing) EEPROM page. + * + * This function writes the contents of an already loaded EEPROM page + * buffer into EEPROM memory. + * + * As this is a split write, the page in EEPROM will _not_ be erased + * before writing. + * + * \param pageAddr EEPROM Page address, between 0 and EEPROM_SIZE/EEPROM_PAGESIZE + */ +void EEPROM_SplitWritePage( uint8_t pageAddr ) +{ + /* Wait until NVM is not busy. */ + EEPROM_WaitForNVM(); + + /* Calculate page address */ + uint16_t address = (uint16_t)(pageAddr*EEPROM_PAGESIZE); + + /* Set address. */ + NVM.ADDR0 = address & 0xFF; + NVM.ADDR1 = (address >> 8) & 0x1F; + NVM.ADDR2 = 0x00; + + /* Issue EEPROM Split Write command. */ + NVM.CMD = NVM_CMD_WRITE_EEPROM_PAGE_gc; + NVM_EXEC(); +} + +/*! \brief Erase entire EEPROM memory. + * + * This function erases the entire EEPROM memory block to 0xFF. + */ +void EEPROM_EraseAll( void ) +{ + /* Wait until NVM is not busy. */ + EEPROM_WaitForNVM(); + + /* Issue EEPROM Erase All command. */ + NVM.CMD = NVM_CMD_ERASE_EEPROM_gc; + NVM_EXEC(); +} + diff --git a/eeprom_driver.h b/eeprom_driver.h new file mode 100644 index 0000000..90cc8e3 --- /dev/null +++ b/eeprom_driver.h @@ -0,0 +1,142 @@ +/* This file has been prepared for Doxygen automatic documentation generation.*/ +/*! \file ********************************************************************* + * + * \brief XMEGA EEPROM driver header file. + * + * This file contains the function prototypes and enumerator definitions + * for various configuration parameters for the XMEGA EEPROM driver. + * + * The driver is not intended for size and/or speed critical code, since + * most functions are just a few lines of code, and the function call + * overhead would decrease code performance. The driver is intended for + * rapid prototyping and documentation purposes for getting started with + * the XMEGA EEPROM module. + * + * For size and/or speed critical code, it is recommended to copy the + * function contents directly into your application instead of making + * a function call. + * + * \par Application note: + * AVR1315: Accessing the XMEGA EEPROM + * + * \par Documentation + * For comprehensive code documentation, supported compilers, compiler + * settings and supported devices see readme.html + * + * \author + * Atmel Corporation: http://www.atmel.com \n + * Support email: avr@atmel.com + * + * $Revision: 1569 $ + * $Date: 2008-04-22 13:03:43 +0200 (ti, 22 apr 2008) $ \n + * + * Copyright (c) 2008, Atmel Corporation All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of ATMEL may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY AND + * SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ +#ifndef EEPROM_DRIVER_H +#define EEPROM_DRIVER_H + +#include "avr_compiler.h" + +#define MAPPED_EEPROM_START 0x1000 +#define EEPROM_PAGESIZE 32 +#define EEPROM(_pageAddr, _byteAddr) \ + ((uint8_t *) MAPPED_EEPROM_START)[_pageAddr*EEPROM_PAGESIZE + _byteAddr] + + + +/* Definitions of macros. */ + +/*! \brief Enable EEPROM block sleep-when-not-used mode. + * + * This macro enables power reduction mode for EEPROM. + * It means that the EEPROM block is disabled when not used. + * Note that there will be a penalty of 6 CPU cycles if EEPROM + * is accessed. + */ +#define EEPROM_EnablePowerReduction() ( NVM.CTRLB |= NVM_EPRM_bm ) + +/*! \brief Disable EEPROM block sleep-when-not-used mode. + * + * This macro disables power reduction mode for EEPROM. + */ +#define EEPROM_DisablePowerReduction() ( NVM.CTRLB &= ~NVM_EPRM_bm ) + +/*! \brief Enable EEPROM mapping into data space. + * + * This macro enables mapping of EEPROM into data space. + * EEPROM starts at EEPROM_START in data memory. Read access + * can be done similar to ordinary SRAM access. + * + * \note This disables IO-mapped access to EEPROM, although page erase and + * write operations still needs to be done through IO register. + */ +#define EEPROM_EnableMapping() ( NVM.CTRLB |= NVM_EEMAPEN_bm ) + +/*! \brief Disable EEPROM mapping into data space. + * + * This macro disables mapping of EEPROM into data space. + * IO mapped access is now enabled. + */ +#define EEPROM_DisableMapping() ( NVM.CTRLB &= ~NVM_EEMAPEN_bm ) + +/*! \brief Non-Volatile Memory Execute Command + * + * This macro set the CCP register before setting the CMDEX bit in the + * NVM.CTRLA register. + * + * \note The CMDEX bit must be set within 4 clock cycles after setting the + * protection byte in the CCP register. + */ +#define NVM_EXEC() asm("push r30" "\n\t" \ + "push r31" "\n\t" \ + "push r16" "\n\t" \ + "push r18" "\n\t" \ + "ldi r30, 0xCB" "\n\t" \ + "ldi r31, 0x01" "\n\t" \ + "ldi r16, 0xD8" "\n\t" \ + "ldi r18, 0x01" "\n\t" \ + "out 0x34, r16" "\n\t" \ + "st Z, r18" "\n\t" \ + "pop r18" "\n\t" \ + "pop r16" "\n\t" \ + "pop r31" "\n\t" \ + "pop r30" "\n\t" \ + ) + +/* Prototyping of functions. */ +void EEPROM_WriteByte( uint8_t pageAddr, uint8_t byteAddr, uint8_t value ); +uint8_t EEPROM_ReadByte( uint8_t pageAddr, uint8_t byteAddr ); +void EEPROM_WaitForNVM( void ); +void EEPROM_FlushBuffer( void ); +void EEPROM_LoadByte( uint8_t byteAddr, uint8_t value ); +void EEPROM_LoadPage( const uint8_t * values ); +void EEPROM_AtomicWritePage( uint8_t pageAddr ); +void EEPROM_ErasePage( uint8_t pageAddress ); +void EEPROM_SplitWritePage( uint8_t pageAddr ); +void EEPROM_EraseAll( void ); + +#endif diff --git a/twi_master_driver.c b/twi_master_driver.c new file mode 100644 index 0000000..c7f9695 --- /dev/null +++ b/twi_master_driver.c @@ -0,0 +1,399 @@ +/* This file has been prepared for Doxygen automatic documentation generation.*/ +/*! \file ********************************************************************* + * + * \brief + * XMEGA TWI master driver source file. + * + * This file contains the function implementations the XMEGA master TWI + * driver. + * + * The driver is not intended for size and/or speed critical code, since + * most functions are just a few lines of code, and the function call + * overhead would decrease code performance. The driver is intended for + * rapid prototyping and documentation purposes for getting started with + * the XMEGA TWI master module. + * + * For size and/or speed critical code, it is recommended to copy the + * function contents directly into your application instead of making + * a function call. + * + * Several functions use the following construct: + * "some_register = ... | (some_parameter ? SOME_BIT_bm : 0) | ..." + * Although the use of the ternary operator ( if ? then : else ) is + * discouraged, in some occasions the operator makes it possible to write + * pretty clean and neat code. In this driver, the construct is used to + * set or not set a configuration bit based on a boolean input parameter, + * such as the "some_parameter" in the example above. + * + * \par Application note: + * AVR1308: Using the XMEGA TWI + * + * \par Documentation + * For comprehensive code documentation, supported compilers, compiler + * settings and supported devices see readme.html + * + * \author + * Atmel Corporation: http://www.atmel.com \n + * Support email: avr@atmel.com + * + * $Revision: 1569 $ + * $Date: 2008-04-22 13:03:43 +0200 (ti, 22 apr 2008) $ \n + * + * Copyright (c) 2008, Atmel Corporation All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of ATMEL may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY AND + * SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +#include "twi_master_driver.h" + + +/*! \brief Initialize the TWI module. + * + * TWI module initialization function. + * Enables master read and write interrupts. + * Remember to enable interrupts globally from the main application. + * + * \param twi The TWI_Master_t struct instance. + * \param module The TWI module to use. + * \param intLevel Master interrupt level. + * \param baudRateRegisterSetting The baud rate register value. + */ +void TWI_MasterInit(TWI_Master_t *twi, + TWI_t *module, + TWI_MASTER_INTLVL_t intLevel, + uint8_t baudRateRegisterSetting) +{ + twi->interface = module; + twi->interface->MASTER.CTRLA = intLevel | + TWI_MASTER_RIEN_bm | + TWI_MASTER_WIEN_bm | + TWI_MASTER_ENABLE_bm; + twi->interface->MASTER.BAUD = baudRateRegisterSetting; + twi->interface->MASTER.STATUS = TWI_MASTER_BUSSTATE_IDLE_gc; +} + + +/*! \brief Returns the TWI bus state. + * + * Returns the TWI bus state (type defined in device headerfile), + * unknown, idle, owner or busy. + * + * \param twi The TWI_Master_t struct instance. + * + * \retval TWI_MASTER_BUSSTATE_UNKNOWN_gc Bus state is unknown. + * \retval TWI_MASTER_BUSSTATE_IDLE_gc Bus state is idle. + * \retval TWI_MASTER_BUSSTATE_OWNER_gc Bus state is owned by the master. + * \retval TWI_MASTER_BUSSTATE_BUSY_gc Bus state is busy. + */ +TWI_MASTER_BUSSTATE_t TWI_MasterState(TWI_Master_t *twi) +{ + TWI_MASTER_BUSSTATE_t twi_status; + twi_status = (TWI_MASTER_BUSSTATE_t) (twi->interface->MASTER.STATUS & + TWI_MASTER_BUSSTATE_gm); + return twi_status; +} + + +/*! \brief Returns true if transaction is ready. + * + * This function returns a boolean whether the TWI Master is ready + * for a new transaction. + * + * \param twi The TWI_Master_t struct instance. + * + * \retval true If transaction could be started. + * \retval false If transaction could not be started. + */ +bool TWI_MasterReady(TWI_Master_t *twi) +{ + bool twi_status = (twi->status & TWIM_STATUS_READY); + return twi_status; +} + + +/*! \brief TWI write transaction. + * + * This function is TWI Master wrapper for a write-only transaction. + * + * \param twi The TWI_Master_t struct instance. + * \param address Slave address. + * \param writeData Pointer to data to write. + * \param bytesToWrite Number of data bytes to write. + * + * \retval true If transaction could be started. + * \retval false If transaction could not be started. + */ +bool TWI_MasterWrite(TWI_Master_t *twi, + uint8_t address, + uint8_t *writeData, + uint8_t bytesToWrite) +{ + bool twi_status = TWI_MasterWriteRead(twi, address, writeData, bytesToWrite, 0); + return twi_status; +} + + +/*! \brief TWI read transaction. + * + * This function is a TWI Maste wrapper for read-only transaction. + * + * \param twi The TWI_Master_t struct instance. + * \param address The slave address. + * \param bytesToRead The number of bytes to read. + * + * \retval true If transaction could be started. + * \retval false If transaction could not be started. + */ +bool TWI_MasterRead(TWI_Master_t *twi, + uint8_t address, + uint8_t bytesToRead) +{ + bool twi_status = TWI_MasterWriteRead(twi, address, 0, 0, bytesToRead); + return twi_status; +} + + +/*! \brief TWI write and/or read transaction. + * + * This function is a TWI Master write and/or read transaction. The function + * can be used to both write and/or read bytes to/from the TWI Slave in one + * transaction. + * + * \param twi The TWI_Master_t struct instance. + * \param address The slave address. + * \param writeData Pointer to data to write. + * \param bytesToWrite Number of bytes to write. + * \param bytesToRead Number of bytes to read. + * + * \retval true If transaction could be started. + * \retval false If transaction could not be started. + */ +bool TWI_MasterWriteRead(TWI_Master_t *twi, + uint8_t address, + uint8_t *writeData, + uint8_t bytesToWrite, + uint8_t bytesToRead) +{ + /*Parameter sanity check. */ + if (bytesToWrite > TWIM_WRITE_BUFFER_SIZE) { + return false; + } + if (bytesToRead > TWIM_READ_BUFFER_SIZE) { + return false; + } + + /*Initiate transaction if bus is ready. */ + if (twi->status == TWIM_STATUS_READY) { + + twi->status = TWIM_STATUS_BUSY; + twi->result = TWIM_RESULT_UNKNOWN; + + twi->address = address<<1; + + /* Fill write data buffer. */ + for (uint8_t bufferIndex=0; bufferIndex < bytesToWrite; bufferIndex++) { + twi->writeData[bufferIndex] = writeData[bufferIndex]; + } + + twi->bytesToWrite = bytesToWrite; + twi->bytesToRead = bytesToRead; + twi->bytesWritten = 0; + twi->bytesRead = 0; + + /* If write command, send the START condition + Address + + * 'R/_W = 0' + */ + if (twi->bytesToWrite > 0) { + uint8_t writeAddress = twi->address & ~0x01; + twi->interface->MASTER.ADDR = writeAddress; + } + + /* If read command, send the START condition + Address + + * 'R/_W = 1' + */ + else if (twi->bytesToRead > 0) { + uint8_t readAddress = twi->address | 0x01; + twi->interface->MASTER.ADDR = readAddress; + } + return true; + } else { + return false; + } +} + + +/*! \brief Common TWI master interrupt service routine. + * + * Check current status and calls the appropriate handler. + * + * \param twi The TWI_Master_t struct instance. + */ +void TWI_MasterInterruptHandler(TWI_Master_t *twi) +{ + uint8_t currentStatus = twi->interface->MASTER.STATUS; + + /* If arbitration lost or bus error. */ + if ((currentStatus & TWI_MASTER_ARBLOST_bm) || + (currentStatus & TWI_MASTER_BUSERR_bm)) { + + TWI_MasterArbitrationLostBusErrorHandler(twi); + } + + /* If master write interrupt. */ + else if (currentStatus & TWI_MASTER_WIF_bm) { + TWI_MasterWriteHandler(twi); + } + + /* If master read interrupt. */ + else if (currentStatus & TWI_MASTER_RIF_bm) { + TWI_MasterReadHandler(twi); + } + + /* If unexpected state. */ + else { + TWI_MasterTransactionFinished(twi, TWIM_RESULT_FAIL); + } +} + + +/*! \brief TWI master arbitration lost and bus error interrupt handler. + * + * Handles TWI responses to lost arbitration and bus error. + * + * \param twi The TWI_Master_t struct instance. + */ +void TWI_MasterArbitrationLostBusErrorHandler(TWI_Master_t *twi) +{ + uint8_t currentStatus = twi->interface->MASTER.STATUS; + + /* If bus error. */ + if (currentStatus & TWI_MASTER_BUSERR_bm) { + twi->result = TWIM_RESULT_BUS_ERROR; + } + /* If arbitration lost. */ + else { + twi->result = TWIM_RESULT_ARBITRATION_LOST; + } + + /* Clear interrupt flag. */ + twi->interface->MASTER.STATUS = currentStatus | TWI_MASTER_ARBLOST_bm; + + twi->status = TWIM_STATUS_READY; +} + + +/*! \brief TWI master write interrupt handler. + * + * Handles TWI transactions (master write) and responses to (N)ACK. + * + * \param twi The TWI_Master_t struct instance. + */ +void TWI_MasterWriteHandler(TWI_Master_t *twi) +{ + /* Local variables used in if tests to avoid compiler warning. */ + uint8_t bytesToWrite = twi->bytesToWrite; + uint8_t bytesToRead = twi->bytesToRead; + + /* If NOT acknowledged (NACK) by slave cancel the transaction. */ + if (twi->interface->MASTER.STATUS & TWI_MASTER_RXACK_bm) { + twi->interface->MASTER.CTRLC = TWI_MASTER_CMD_STOP_gc; + twi->result = TWIM_RESULT_NACK_RECEIVED; + twi->status = TWIM_STATUS_READY; + } + + /* If more bytes to write, send data. */ + else if (twi->bytesWritten < bytesToWrite) { + uint8_t data = twi->writeData[twi->bytesWritten]; + twi->interface->MASTER.DATA = data; + ++twi->bytesWritten; + } + + /* If bytes to read, send repeated START condition + Address + + * 'R/_W = 1' + */ + else if (twi->bytesRead < bytesToRead) { + uint8_t readAddress = twi->address | 0x01; + twi->interface->MASTER.ADDR = readAddress; + } + + /* If transaction finished, send STOP condition and set RESULT OK. */ + else { + twi->interface->MASTER.CTRLC = TWI_MASTER_CMD_STOP_gc; + TWI_MasterTransactionFinished(twi, TWIM_RESULT_OK); + } +} + + +/*! \brief TWI master read interrupt handler. + * + * This is the master read interrupt handler that takes care of + * reading bytes from the TWI slave. + * + * \param twi The TWI_Master_t struct instance. + */ +void TWI_MasterReadHandler(TWI_Master_t *twi) +{ + /* Fetch data if bytes to be read. */ + if (twi->bytesRead < TWIM_READ_BUFFER_SIZE) { + uint8_t data = twi->interface->MASTER.DATA; + twi->readData[twi->bytesRead] = data; + twi->bytesRead++; + } + + /* If buffer overflow, issue STOP and BUFFER_OVERFLOW condition. */ + else { + twi->interface->MASTER.CTRLC = TWI_MASTER_CMD_STOP_gc; + TWI_MasterTransactionFinished(twi, TWIM_RESULT_BUFFER_OVERFLOW); + } + + /* Local variable used in if test to avoid compiler warning. */ + uint8_t bytesToRead = twi->bytesToRead; + + /* If more bytes to read, issue ACK and start a byte read. */ + if (twi->bytesRead < bytesToRead) { + twi->interface->MASTER.CTRLC = TWI_MASTER_CMD_RECVTRANS_gc; + } + + /* If transaction finished, issue NACK and STOP condition. */ + else { + twi->interface->MASTER.CTRLC = TWI_MASTER_ACKACT_bm | + TWI_MASTER_CMD_STOP_gc; + TWI_MasterTransactionFinished(twi, TWIM_RESULT_OK); + } +} + + +/*! \brief TWI transaction finished handler. + * + * Prepares module for new transaction. + * + * \param twi The TWI_Master_t struct instance. + * \param result The result of the operation. + */ +void TWI_MasterTransactionFinished(TWI_Master_t *twi, uint8_t result) +{ + twi->result = result; + twi->status = TWIM_STATUS_READY; +} diff --git a/twi_master_driver.h b/twi_master_driver.h new file mode 100644 index 0000000..c6620f7 --- /dev/null +++ b/twi_master_driver.h @@ -0,0 +1,147 @@ +/* This file has been prepared for Doxygen automatic documentation generation.*/ +/*! \file ********************************************************************* + * + * \brief XMEGA TWI master driver header file. + * + * This file contains the function prototypes and enumerator definitions + * for various configuration parameters for the XMEGA TWI master driver. + * + * The driver is not intended for size and/or speed critical code, since + * most functions are just a few lines of code, and the function call + * overhead would decrease code performance. The driver is intended for + * rapid prototyping and documentation purposes for getting started with + * the XMEGA TWI master module. + * + * For size and/or speed critical code, it is recommended to copy the + * function contents directly into your application instead of making + * a function call. + * + * \par Application note: + * AVR1308: Using the XMEGA TWI + * + * \par Documentation + * For comprehensive code documentation, supported compilers, compiler + * settings and supported devices see readme.html + * + * \author + * Atmel Corporation: http://www.atmel.com \n + * Support email: avr@atmel.com + * + * $Revision: 1569 $ + * $Date: 2008-04-22 13:03:43 +0200 (ti, 22 apr 2008) $ \n + * + * Copyright (c) 2008, Atmel Corporation All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of ATMEL may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY AND + * SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ +#ifndef TWI_MASTER_DRIVER_H +#define TWI_MASTER_DRIVER_H + +#include "avr_compiler.h" + +/*! Baud register setting calculation. Formula described in datasheet. */ +#define TWI_BAUD(F_SYS, F_TWI) ((F_SYS / (2 * F_TWI)) - 5) + + +/*! Transaction status defines. */ +#define TWIM_STATUS_READY 0 +#define TWIM_STATUS_BUSY 1 + + +/*! Transaction result enumeration. */ +typedef enum TWIM_RESULT_enum { + TWIM_RESULT_UNKNOWN = (0x00<<0), + TWIM_RESULT_OK = (0x01<<0), + TWIM_RESULT_BUFFER_OVERFLOW = (0x02<<0), + TWIM_RESULT_ARBITRATION_LOST = (0x03<<0), + TWIM_RESULT_BUS_ERROR = (0x04<<0), + TWIM_RESULT_NACK_RECEIVED = (0x05<<0), + TWIM_RESULT_FAIL = (0x06<<0), +} TWIM_RESULT_t; + +/*! Buffer size defines */ +#define TWIM_WRITE_BUFFER_SIZE 8 +#define TWIM_READ_BUFFER_SIZE 8 + + +/*! \brief TWI master driver struct + * + * TWI master struct. Holds pointer to TWI module, + * buffers and necessary varibles. + */ +typedef struct TWI_Master { + TWI_t *interface; /*!< Pointer to what interface to use */ + register8_t address; /*!< Slave address */ + register8_t writeData[TWIM_WRITE_BUFFER_SIZE]; /*!< Data to write */ + register8_t readData[TWIM_READ_BUFFER_SIZE]; /*!< Read data */ + register8_t bytesToWrite; /*!< Number of bytes to write */ + register8_t bytesToRead; /*!< Number of bytes to read */ + register8_t bytesWritten; /*!< Number of bytes written */ + register8_t bytesRead; /*!< Number of bytes read */ + register8_t status; /*!< Status of transaction */ + register8_t result; /*!< Result of transaction */ +}TWI_Master_t; + + + +void TWI_MasterInit(TWI_Master_t *twi, + TWI_t *module, + TWI_MASTER_INTLVL_t intLevel, + uint8_t baudRateRegisterSetting); +TWI_MASTER_BUSSTATE_t TWI_MasterState(TWI_Master_t *twi); +bool TWI_MasterReady(TWI_Master_t *twi); +bool TWI_MasterWrite(TWI_Master_t *twi, + uint8_t address, + uint8_t * writeData, + uint8_t bytesToWrite); +bool TWI_MasterRead(TWI_Master_t *twi, + uint8_t address, + uint8_t bytesToRead); +bool TWI_MasterWriteRead(TWI_Master_t *twi, + uint8_t address, + uint8_t *writeData, + uint8_t bytesToWrite, + uint8_t bytesToRead); +void TWI_MasterInterruptHandler(TWI_Master_t *twi); +void TWI_MasterArbitrationLostBusErrorHandler(TWI_Master_t *twi); +void TWI_MasterWriteHandler(TWI_Master_t *twi); +void TWI_MasterReadHandler(TWI_Master_t *twi); +void TWI_MasterTransactionFinished(TWI_Master_t *twi, uint8_t result); + + +/*! TWI master interrupt service routine. + * + * Interrupt service routine for the TWI master. Copy the needed vectors + * into your code. + * + ISR(TWIC_TWIM_vect) + { + TWI_MasterInterruptHandler(&twiMaster); + } + + * + */ + +#endif /* TWI_MASTER_DRIVER_H */ diff --git a/twi_slave_driver.c b/twi_slave_driver.c new file mode 100644 index 0000000..d6eecc2 --- /dev/null +++ b/twi_slave_driver.c @@ -0,0 +1,321 @@ +/* This file has been prepared for Doxygen automatic documentation generation.*/ +/*! \file ********************************************************************* + * + * \brief + * XMEGA TWI slave driver source file. + * + * This file contains the function implementations the XMEGA TWI slave + * driver. + * + * The driver is not intended for size and/or speed critical code, since + * most functions are just a few lines of code, and the function call + * overhead would decrease code performance. The driver is intended for + * rapid prototyping and documentation purposes for getting started with + * the XMEGA TWI slave module. + * + * For size and/or speed critical code, it is recommended to copy the + * function contents directly into your application instead of making + * a function call. + * + * Several functions use the following construct: + * "some_register = ... | (some_parameter ? SOME_BIT_bm : 0) | ..." + * Although the use of the ternary operator ( if ? then : else ) is + * discouraged, in some occasions the operator makes it possible to write + * pretty clean and neat code. In this driver, the construct is used to + * set or not set a configuration bit based on a boolean input parameter, + * such as the "some_parameter" in the example above. + * + * \par Application note: + * AVR1308: Using the XMEGA TWI + * + * \par Documentation + * For comprehensive code documentation, supported compilers, compiler + * settings and supported devices see readme.html + * + * \author + * Atmel Corporation: http://www.atmel.com \n + * Support email: avr@atmel.com + * + * $Revision: 2660 $ + * $Date: 2009-08-11 12:28:58 +0200 (ti, 11 aug 2009) $ \n + * + * Copyright (c) 2008, Atmel Corporation All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of ATMEL may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY AND + * SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +#include "twi_slave_driver.h" + + +/*! \brief Initalizes TWI slave driver structure. + * + * Initialize the instance of the TWI Slave and set the appropriate values. + * + * \param twi The TWI_Slave_t struct instance. + * \param module Pointer to the TWI module. + * \param processDataFunction Pointer to the function that handles incoming data. + */ +void TWI_SlaveInitializeDriver(TWI_Slave_t *twi, + TWI_t *module, + void (*processDataFunction) (void)) +{ + twi->interface = module; + twi->Process_Data = processDataFunction; + twi->bytesReceived = 0; + twi->bytesSent = 0; + twi->status = TWIS_STATUS_READY; + twi->result = TWIS_RESULT_UNKNOWN; + twi->abort = false; +} + + +/*! \brief Initialize the TWI module. + * + * Enables interrupts on address recognition and data available. + * Remember to enable interrupts globally from the main application. + * + * \param twi The TWI_Slave_t struct instance. + * \param address Slave address for this module. + * \param intLevel Interrupt level for the TWI slave interrupt handler. + */ +void TWI_SlaveInitializeModule(TWI_Slave_t *twi, + uint8_t address, + TWI_SLAVE_INTLVL_t intLevel) +{ + twi->interface->SLAVE.CTRLA = intLevel | + TWI_SLAVE_DIEN_bm | + TWI_SLAVE_APIEN_bm | + TWI_SLAVE_ENABLE_bm; + twi->interface->SLAVE.ADDR = (address<<1); +} + + +/*! \brief Common TWI slave interrupt service routine. + * + * Handles all TWI transactions and responses to address match, data reception, + * data transmission, bus error and data collision. + * + * \param twi The TWI_Slave_t struct instance. + */ +void TWI_SlaveInterruptHandler(TWI_Slave_t *twi) +{ + uint8_t currentStatus = twi->interface->SLAVE.STATUS; + + /* If bus error. */ + if (currentStatus & TWI_SLAVE_BUSERR_bm) { + twi->bytesReceived = 0; + twi->bytesSent = 0; + twi->result = TWIS_RESULT_BUS_ERROR; + twi->status = TWIS_STATUS_READY; + } + + /* If transmit collision. */ + else if (currentStatus & TWI_SLAVE_COLL_bm) { + twi->bytesReceived = 0; + twi->bytesSent = 0; + twi->result = TWIS_RESULT_TRANSMIT_COLLISION; + twi->status = TWIS_STATUS_READY; + } + + /* If address match. */ + else if ((currentStatus & TWI_SLAVE_APIF_bm) && + (currentStatus & TWI_SLAVE_AP_bm)) { + + TWI_SlaveAddressMatchHandler(twi); + } + + /* If stop (only enabled through slave read transaction). */ + else if (currentStatus & TWI_SLAVE_APIF_bm) { + TWI_SlaveStopHandler(twi); + } + + /* If data interrupt. */ + else if (currentStatus & TWI_SLAVE_DIF_bm) { + TWI_SlaveDataHandler(twi); + } + + /* If unexpected state. */ + else { + TWI_SlaveTransactionFinished(twi, TWIS_RESULT_FAIL); + } +} + +/*! \brief TWI address match interrupt handler. + * + * Prepares TWI module for transaction when an address match occures. + * + * \param twi The TWI_Slave_t struct instance. + */ +void TWI_SlaveAddressMatchHandler(TWI_Slave_t *twi) +{ + /* If application signalling need to abort (error occured). */ + if (twi->abort) { + twi->interface->SLAVE.CTRLB = TWI_SLAVE_CMD_COMPTRANS_gc; + TWI_SlaveTransactionFinished(twi, TWIS_RESULT_ABORTED); + twi->abort = false; + } else { + twi->status = TWIS_STATUS_BUSY; + twi->result = TWIS_RESULT_UNKNOWN; + + /* Disable stop interrupt. */ + uint8_t currentCtrlA = twi->interface->SLAVE.CTRLA; + twi->interface->SLAVE.CTRLA = currentCtrlA & ~TWI_SLAVE_PIEN_bm; + + twi->bytesReceived = 0; + twi->bytesSent = 0; + + /* Send ACK, wait for data interrupt. */ + twi->interface->SLAVE.CTRLB = TWI_SLAVE_CMD_RESPONSE_gc; + } +} + + +/*! \brief TWI stop condition interrupt handler. + * + * \param twi The TWI_Slave_t struct instance. + */ +void TWI_SlaveStopHandler(TWI_Slave_t *twi) +{ + /* Disable stop interrupt. */ + uint8_t currentCtrlA = twi->interface->SLAVE.CTRLA; + twi->interface->SLAVE.CTRLA = currentCtrlA & ~TWI_SLAVE_PIEN_bm; + + /* Clear APIF, according to flowchart don't ACK or NACK */ + uint8_t currentStatus = twi->interface->SLAVE.STATUS; + twi->interface->SLAVE.STATUS = currentStatus | TWI_SLAVE_APIF_bm; + + TWI_SlaveTransactionFinished(twi, TWIS_RESULT_OK); + +} + + +/*! \brief TWI data interrupt handler. + * + * Calls the appropriate slave read or write handler. + * + * \param twi The TWI_Slave_t struct instance. + */ +void TWI_SlaveDataHandler(TWI_Slave_t *twi) +{ + if (twi->interface->SLAVE.STATUS & TWI_SLAVE_DIR_bm) { + TWI_SlaveWriteHandler(twi); + } else { + TWI_SlaveReadHandler(twi); + } +} + + +/*! \brief TWI slave read interrupt handler. + * + * Handles TWI slave read transactions and responses. + * + * \param twi The TWI_Slave_t struct instance. + */ +void TWI_SlaveReadHandler(TWI_Slave_t *twi) +{ + /* Enable stop interrupt. */ + uint8_t currentCtrlA = twi->interface->SLAVE.CTRLA; + twi->interface->SLAVE.CTRLA = currentCtrlA | TWI_SLAVE_PIEN_bm; + + /* If free space in buffer. */ + if (twi->bytesReceived < TWIS_RECEIVE_BUFFER_SIZE) { + /* Fetch data */ + uint8_t data = twi->interface->SLAVE.DATA; + twi->receivedData[twi->bytesReceived] = data; + + /* Process data. */ + twi->Process_Data(); + + twi->bytesReceived++; + + /* If application signalling need to abort (error occured), + * complete transaction and wait for next START. Otherwise + * send ACK and wait for data interrupt. + */ + if (twi->abort) { + twi->interface->SLAVE.CTRLB = TWI_SLAVE_CMD_COMPTRANS_gc; + TWI_SlaveTransactionFinished(twi, TWIS_RESULT_ABORTED); + twi->abort = false; + } else { + twi->interface->SLAVE.CTRLB = TWI_SLAVE_CMD_RESPONSE_gc; + } + } + /* If buffer overflow, send NACK and wait for next START. Set + * result buffer overflow. + */ + else { + twi->interface->SLAVE.CTRLB = TWI_SLAVE_ACKACT_bm | + TWI_SLAVE_CMD_COMPTRANS_gc; + TWI_SlaveTransactionFinished(twi, TWIS_RESULT_BUFFER_OVERFLOW); + } +} + + +/*! \brief TWI slave write interrupt handler. + * + * Handles TWI slave write transactions and responses. + * + * \param twi The TWI_Slave_t struct instance. + */ +void TWI_SlaveWriteHandler(TWI_Slave_t *twi) +{ + /* If NACK, slave write transaction finished. */ + if ((twi->bytesSent > 0) && (twi->interface->SLAVE.STATUS & + TWI_SLAVE_RXACK_bm)) { + + twi->interface->SLAVE.CTRLB = TWI_SLAVE_CMD_COMPTRANS_gc; + TWI_SlaveTransactionFinished(twi, TWIS_RESULT_OK); + } + /* If ACK, master expects more data. */ + else { + if (twi->bytesSent < TWIS_SEND_BUFFER_SIZE) { + uint8_t data = twi->sendData[twi->bytesSent]; + twi->interface->SLAVE.DATA = data; + twi->bytesSent++; + + /* Send data, wait for data interrupt. */ + twi->interface->SLAVE.CTRLB = TWI_SLAVE_CMD_RESPONSE_gc; + } + /* If buffer overflow. */ + else { + twi->interface->SLAVE.CTRLB = TWI_SLAVE_CMD_COMPTRANS_gc; + TWI_SlaveTransactionFinished(twi, TWIS_RESULT_BUFFER_OVERFLOW); + } + } +} + + +/*! \brief TWI transaction finished function. + * + * Prepares module for new transaction. + * + * \param twi The TWI_Slave_t struct instance. + * \param result The result of the transaction. + */ +void TWI_SlaveTransactionFinished(TWI_Slave_t *twi, uint8_t result) +{ + twi->result = result; + twi->status = TWIS_STATUS_READY; +} diff --git a/twi_slave_driver.h b/twi_slave_driver.h new file mode 100644 index 0000000..c09c43b --- /dev/null +++ b/twi_slave_driver.h @@ -0,0 +1,135 @@ +/* This file has been prepared for Doxygen automatic documentation generation.*/ +/*! \file ********************************************************************* + * + * \brief XMEGA TWI slave driver header file. + * + * This file contains the function prototypes and enumerator definitions + * for various configuration parameters for the XMEGA TWI slave driver. + * + * The driver is not intended for size and/or speed critical code, since + * most functions are just a few lines of code, and the function call + * overhead would decrease code performance. The driver is intended for + * rapid prototyping and documentation purposes for getting started with + * the XMEGA TWI slave module. + * + * For size and/or speed critical code, it is recommended to copy the + * function contents directly into your application instead of making + * a function call. + * + * \par Application note: + * AVR1307: Using the XMEGA TWI + * + * \par Documentation + * For comprehensive code documentation, supported compilers, compiler + * settings and supported devices see readme.html + * + * \author + * Atmel Corporation: http://www.atmel.com \n + * Support email: avr@atmel.com + * + * $Revision: 1569 $ + * $Date: 2008-04-22 13:03:43 +0200 (ti, 22 apr 2008) $ \n + * + * Copyright (c) 2008, Atmel Corporation All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of ATMEL may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY AND + * SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ +#ifndef TWI_DRIVER_H +#define TWI_DRIVER_H + +#include "avr_compiler.h" + + +/* Transaction status defines.*/ +#define TWIS_STATUS_READY 0 +#define TWIS_STATUS_BUSY 1 + +/* Transaction result enumeration */ +typedef enum TWIS_RESULT_enum { + TWIS_RESULT_UNKNOWN = (0x00<<0), + TWIS_RESULT_OK = (0x01<<0), + TWIS_RESULT_BUFFER_OVERFLOW = (0x02<<0), + TWIS_RESULT_TRANSMIT_COLLISION = (0x03<<0), + TWIS_RESULT_BUS_ERROR = (0x04<<0), + TWIS_RESULT_FAIL = (0x05<<0), + TWIS_RESULT_ABORTED = (0x06<<0), +} TWIS_RESULT_t; + +/* Buffer size defines. */ +#define TWIS_RECEIVE_BUFFER_SIZE 8 +#define TWIS_SEND_BUFFER_SIZE 8 + + + +/*! \brief TWI slave driver struct. + * + * TWI slave struct. Holds pointer to TWI module and data processing routine, + * buffers and necessary varibles. + */ +typedef struct TWI_Slave { + TWI_t *interface; /*!< Pointer to what interface to use*/ + void (*Process_Data) (void); /*!< Pointer to process data function*/ + register8_t receivedData[TWIS_RECEIVE_BUFFER_SIZE]; /*!< Read data*/ + register8_t sendData[TWIS_SEND_BUFFER_SIZE]; /*!< Data to write*/ + register8_t bytesReceived; /*!< Number of bytes received*/ + register8_t bytesSent; /*!< Number of bytes sent*/ + register8_t status; /*!< Status of transaction*/ + register8_t result; /*!< Result of transaction*/ + bool abort; /*!< Strobe to abort*/ +} TWI_Slave_t; + + + +void TWI_SlaveInitializeDriver(TWI_Slave_t *twi, + TWI_t *module, + void (*processDataFunction) (void)); + +void TWI_SlaveInitializeModule(TWI_Slave_t *twi, + uint8_t address, + TWI_SLAVE_INTLVL_t intLevel); + +void TWI_SlaveInterruptHandler(TWI_Slave_t *twi); +void TWI_SlaveAddressMatchHandler(TWI_Slave_t *twi); +void TWI_SlaveStopHandler(TWI_Slave_t *twi); +void TWI_SlaveDataHandler(TWI_Slave_t *twi); +void TWI_SlaveReadHandler(TWI_Slave_t *twi); +void TWI_SlaveWriteHandler(TWI_Slave_t *twi); +void TWI_SlaveTransactionFinished(TWI_Slave_t *twi, uint8_t result); + + +/*! TWI slave interrupt service routine. + * + * Interrupt service routine for the TWI slave. Copy the interrupt vector + * into your code if needed. + * + ISR(TWIC_TWIS_vect) + { + TWI_SlaveInterruptHandler(&twiSlaveC); + } + * + */ + + +#endif /* TWI_DRIVER_H */ -- cgit v1.2.3