/*! \file at24cxx.c \brief the read and write function file \version 2021-10-30, V1.0.0, firmware for GD32W51x */ /* Copyright (c) 2021, GigaDevice Semiconductor Inc. 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. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 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 "at24cxx.h" #include "i2c.h" #include #define EEPROM_BLOCK0_ADDRESS 0xA0 #define BUFFER_SIZE 256 #define MAX_RELOAD_SIZE 255 uint16_t eeprom_address; /*! \brief I2C read and write functions \param[in] none \param[out] none \retval I2C_OK or I2C_FAIL */ uint8_t i2c_24c02_test(void) { uint16_t i; uint8_t i2c_buffer_write[BUFFER_SIZE]; uint8_t i2c_buffer_read[BUFFER_SIZE]; printf("\r\nAT24C02 writing...\r\n"); /* initialize i2c_buffer_write */ for(i = 0; i < BUFFER_SIZE; i++){ i2c_buffer_write[i] = i; printf("0x%02X ", i2c_buffer_write[i]); if(15 == i%16){ printf("\r\n"); } } /* EEPROM data write */ eeprom_buffer_write(i2c_buffer_write, EEP_FIRST_PAGE, BUFFER_SIZE); printf("AT24C02 reading...\r\n"); /* EEPROM data read */ eeprom_buffer_read(i2c_buffer_read,EEP_FIRST_PAGE, BUFFER_SIZE); /* compare the read buffer and write buffer */ for(i = 0;i < BUFFER_SIZE; i++){ if(i2c_buffer_read[i] != i2c_buffer_write[i]){ printf("0x%02X ", i2c_buffer_read[i]); printf("Err:data read and write aren't matching.\n\r"); return I2C_FAIL; } printf("0x%02X ", i2c_buffer_read[i]); if(15 == i%16){ printf("\r\n"); } } printf("I2C-AT24C02 test passed!\n\r"); return I2C_OK; } /*! \brief initialize peripherals used by the I2C EEPROM driver \param[in] none \param[out] none \retval none */ void i2c_eeprom_init() { eeprom_address = EEPROM_BLOCK0_ADDRESS; } /*! \brief write buffer of data to the I2C EEPROM \param[in] p_buffer: pointer to the buffer containing the data to be written to the EEPROM \param[in] write_address: EEPROM's internal address to write to \param[in] number_of_byte: number of bytes to write to the EEPROM \param[out] none \retval none */ void eeprom_buffer_write(uint8_t* p_buffer, uint8_t write_address, uint16_t number_of_byte) { uint8_t number_of_page = 0, number_of_single = 0, address = 0, count = 0; address = write_address % I2C_PAGE_SIZE; count = I2C_PAGE_SIZE - address; number_of_page = number_of_byte / I2C_PAGE_SIZE; number_of_single = number_of_byte % I2C_PAGE_SIZE; /* if write_address is I2C_PAGE_SIZE aligned */ if(0 == address){ while(number_of_page--){ eeprom_page_write(p_buffer, write_address, I2C_PAGE_SIZE); delay_1ms(5); write_address += I2C_PAGE_SIZE; p_buffer += I2C_PAGE_SIZE; } if(0 != number_of_single){ eeprom_page_write(p_buffer, write_address, number_of_single); delay_1ms(5); } }else{ /* if write_address is not I2C_PAGE_SIZE aligned */ if(number_of_byte < count){ eeprom_page_write(p_buffer, write_address, number_of_byte); delay_1ms(5); }else{ number_of_byte -= count; number_of_page = number_of_byte / I2C_PAGE_SIZE; number_of_single = number_of_byte % I2C_PAGE_SIZE; if(0 != count){ eeprom_page_write(p_buffer, write_address, count); delay_1ms(5); write_address += count; p_buffer += count; } /* write page */ while(number_of_page--){ eeprom_page_write(p_buffer, write_address, I2C_PAGE_SIZE); delay_1ms(5); write_address += I2C_PAGE_SIZE; p_buffer += I2C_PAGE_SIZE; } /* write single */ if(0 != number_of_single){ eeprom_page_write(p_buffer, write_address, number_of_single); delay_1ms(5); } } } } /*! \brief write more than one byte to the EEPROM with a single write cycle \param[in] p_buffer: pointer to the buffer containing the data to be written to the EEPROM \param[in] write_address: EEPROM's internal address to write to \param[in] number_of_byte: number of bytes to write to the EEPROM \param[out] none \retval none */ void eeprom_page_write(uint8_t* p_buffer, uint8_t write_address, uint8_t number_of_byte) { i2c_process_enum state = I2C_START; uint16_t timeout = 0; uint8_t end_flag = 0; uint8_t* p_txbuffer; uint8_t tx_buffer[9] = {0}; dma_single_data_parameter_struct dma_init_struct; tx_buffer[0] = write_address; for(int i=1; i MAX_RELOAD_SIZE){ number_of_byte = number_of_byte - MAX_RELOAD_SIZE; nbytes_reload = MAX_RELOAD_SIZE; }else{ nbytes_reload = number_of_byte; } if(1 == first_reload_flag){ /* configure number of bytes to be transferred */ i2c_transfer_byte_number_config(I2CX, nbytes_reload); first_reload_flag = 0; /* initialize DMA0 channel2 for I2C_RX */ dma_deinit(DMA0, DMA_CH2); dma_single_data_para_struct_init(&dma_init_struct); dma_init_struct.direction = DMA_PERIPH_TO_MEMORY; dma_init_struct.memory0_addr = (uint32_t)p_buffer; dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE; dma_init_struct.periph_memory_width = DMA_MEMORY_WIDTH_8BIT; dma_init_struct.circular_mode = DMA_CIRCULAR_MODE_DISABLE; dma_init_struct.number = nbytes_reload; dma_init_struct.periph_addr = (uint32_t)&I2C_RDATA(I2CX); dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE; dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH; dma_single_data_mode_init(DMA0, DMA_CH2, &dma_init_struct); /* DMA channel peripheral select */ dma_channel_subperipheral_select(DMA0, DMA_CH2, DMA_SUBPERI7); /* enable I2CX receive DMA */ i2c_dma_enable(I2CX, I2C_DMA_RECEIVE); /* enable DMA channel2 for I2CX receive */ dma_channel_enable(DMA0, DMA_CH2); state = I2C_START; }else{ /* wait for TCR flag */ while((!i2c_flag_get(I2CX, I2C_FLAG_TCR)) && (timeout < I2C_TIME_OUT)){ timeout++; } if(timeout < I2C_TIME_OUT){ p_buffer = p_buffer + 255; /* configure number of bytes to be transferred */ i2c_transfer_byte_number_config(I2CX, nbytes_reload); /* disable I2C reload mode */ if(number_of_byte <= MAX_RELOAD_SIZE){ i2c_reload_disable(I2CX); /* enable I2C automatic end mode in master mode */ i2c_automatic_end_enable(I2CX); } timeout = 0; /* disable DMA channel2 */ dma_channel_disable(DMA0, DMA_CH2); dma_init_struct.memory0_addr = (uint32_t)p_buffer; dma_init_struct.number = nbytes_reload; dma_single_data_mode_init(DMA0, DMA_CH2, &dma_init_struct); /* enable DMA channel2 */ dma_channel_enable(DMA0, DMA_CH2); state = I2C_TRANSMIT_DATA; }else{ timeout = 0; state = I2C_START; printf("i2c master reload data timeout in read!\n"); } } break; case I2C_TRANSMIT_DATA: while(!dma_flag_get(DMA0, DMA_CH2, DMA_FLAG_FTF)); if(timeout < I2C_TIME_OUT){ dma_flag_clear(DMA0, DMA_CH2, DMA_FLAG_FTF); /* check if the reload mode is enabled or not */ if(I2C_CTL1(I2CX) & I2C_CTL1_RELOAD){ timeout = 0; state = I2C_RELOAD; }else{ timeout = 0; state = I2C_STOP; } }else{ /* wait DAM FTF timeout */ timeout = 0; state = I2C_START; printf("i2c master read data timeout in read!\n"); } break; case I2C_STOP: /* wait until the stop condition is finished */ while((!i2c_flag_get(I2CX, I2C_FLAG_STPDET)) && (timeout < I2C_TIME_OUT)){ timeout++; } if(timeout < I2C_TIME_OUT){ /* clear STPDET flag */ i2c_flag_clear(I2CX, I2C_FLAG_STPDET); timeout = 0; state = I2C_END; end_flag = 1; }else{ timeout = 0; state = I2C_START; printf("i2c master sends stop signal timeout in read!\n"); } break; default: /* default status */ state = I2C_START; end_flag = 1; timeout = 0; printf("i2c master sends start signal in read!\n"); break; } } }