diff --git a/Vinclude/V_UserMemory.h b/Vinclude/V_UserMemory.h index 4ee9bbc..669a534 100644 --- a/Vinclude/V_UserMemory.h +++ b/Vinclude/V_UserMemory.h @@ -16,9 +16,9 @@ \file V_UserMemory.h \brief Работа с энергонезависимой памятью 1921BK01 (см. TUserMemory) \author ООО "НПФ Вектор". http://motorcontrol.ru - \version v 2.0 25/03/2016 + \version v 2.0 10/08/2019 - \defgroup V_UserMemory Работа с энергонезависимой памятью (см. TUserMemory) + \defgroup V_UserMemory Оболочка для I2CMEM (см. TUserMemory) @{ */ @@ -35,13 +35,15 @@ extern "C" { /*! \class TUserMemory - \brief Работа с пользовательской энергонезависимой памятью МС01 + \brief Работа с пользовательской энергонезависимой памятью I2c + + Класс \a TUserMemory, основанный на структуре TUserMemory, представляет собой оболочку для драйвера для работы с + flash памятью по интерфейсу I2C.\n + Оболочка нужна для совместимости с другими проектами, где используется UserMem \n - Класс \a TUserMemory, основанный на структуре TUserMemory, представляет собой драйвер для работы с - flash памятью.\n пример использования:\n для инициализации\n - spimem.init.(&spimem);\n + UserMem.init(&UserMem);\n для записи\n UserMem.spiaddr=0;\n @@ -52,58 +54,29 @@ extern "C" { */ //! см. TUserMemory -#define USERMEMORY_USERFLASH_KEY 0xA4420000 -#define USERMEMORY_MAX_WAITCLOCKS 2000 -#define USERMEMORY_WRITE_HARDFAULT 0x1 -#define USERMEMORY_WRITE_TIMEOUT 0x2 -#define USERMEMORY_READ_HARDFAULT 0x3 -#define USERMEMORY_READ_TIMEOUT 0x4 -#define USERMEMORY_OP_OK 0x0 - - -#define USERMEMORY_PAGE_SIZE 256 - - -#define USERMEMORY_CMD_WRITE (1<<0) -#define USERMEMORY_CMD_PAGE_ERASE (1<<1) -#define USERMEMORY_CMD_FULL_ERASE (1<2) -#define USERMEMORY_CMD_READ (1<<3) - - struct SUserMemory {Uint16 MemStartAddr;//!Адрес на flash - Uint8 *MCUStartAddr8; //!адрес на массив с данными как байтовый указатель Uint16 *MCUStartAddr; //!адрес на массив с данными Uint16 data_length;//!длина данных int16 receivedCode;//!Статус операции - Uint16 waitClocks;//!Счетчик для ожидания таймаута операции - Uint16 PageInCache;//!Номер текущей закешированной страницы - Uint16 autoFlushCounter;//!Счетчик для сохранения кеша на флеш по таймауту - Uint8 PageRAM_and_FLASH_IdenticalFlag;//!Флаг о том, что данные в кеше и на флеше идентичны - Uint8 NeedFlushRequest;//флаг запроса на запись данных из кеша на флеш - Uint8 cacheArr[USERMEMORY_PAGE_SIZE];//кеш данных - одна страница памяти void (*init)(struct SUserMemory*); void (*write)(struct SUserMemory*); void (*read)(struct SUserMemory*); - void (*full_erase)(struct SUserMemory*); - void (*flush)(struct SUserMemory*); void (*ms_calc)(struct SUserMemory*); void (*slow_calc)(struct SUserMemory*); + void (*full_erase)(struct SUserMemory*); }; typedef struct SUserMemory TUserMemory; //!Инициализатор по умолчанию -#define USERMEMORY_DEFAULTS {0,0,0,0,0,0,0,0,0,0, \ - {0},\ - USERMEMORY_Init, \ - USERMEMORY_Write,\ - USERMEMORY_Read,\ - USERMEMORY_Full_Erase,\ - USERMEMORY_Flush,\ - USERMEMORY_ms_calc,\ - USERMEMORY_slow_calc,\ - } +#define USERMEMORY_DEFAULTS {.init = USERMEMORY_Init, \ + .write = USERMEMORY_Write,\ + .read = USERMEMORY_Read,\ + .ms_calc = USERMEMORY_ms_calc,\ + .slow_calc = USERMEMORY_slow_calc,\ + .full_erase = USERMEMORY_Full_Erase,\ + } //! \memberof TUserMemory @@ -115,17 +88,10 @@ void USERMEMORY_Read(TUserMemory*); //! \memberof TUserMemory void USERMEMORY_Full_Erase(TUserMemory*); //! \memberof TUserMemory -void USERMEMORY_ReadToCache(TUserMemory *p, int16 pageNum); -//! \memberof TUserMemory -void USERMEMORY_WriteFromCache(TUserMemory *p, int16 pageNum); -//! \memberof TUserMemory -void USERMEMORY_Flush(TUserMemory *p); -//! \memberof TUserMemory void USERMEMORY_ms_calc(TUserMemory *p); //! \memberof TUserMemory void USERMEMORY_slow_calc(TUserMemory *p); -//! \memberof TUserMemory -void USERMEMORY_UpdateCurrentPage(TUserMemory *p, Uint16 spiaddr); + #ifdef __cplusplus } diff --git a/Vinclude/V_i2cMem.h b/Vinclude/V_i2cMem.h new file mode 100644 index 0000000..e72bc7b --- /dev/null +++ b/Vinclude/V_i2cMem.h @@ -0,0 +1,42 @@ +/* + * V_i2cMem.h + * + * Created on: 15 авг. 2019 г. + * Author: Dmitry + */ + +#ifndef INCLUDE_V_I2CMEM_H_ +#define INCLUDE_V_I2CMEM_H_ + +#define EEPROM_MEM_LENGTH 32768 //длина флешки в байтах (256 кбит) + +struct SI2cMem; +typedef volatile struct SI2cMem TI2cMem; + +struct SI2cMem { + Uint16 MEMstartaddr; //! Адрес на flash + Uint16 data_length; //! Длина данных в байтах + Uint16 *DSPstartaddr; //! Адрес на массив с данными + Uint16 LastErr; //! Код ошибки (если возникла) + void (*init)(TI2cMem*); + void (*write)(TI2cMem*); + void (*read)(TI2cMem*); + void (*clearMem)(TI2cMem*); + }; + + +void I2CMEM_Init(TI2cMem*); +void I2CMEM_Write(TI2cMem*); +void I2CMEM_Read(TI2cMem*); +void I2CMEM_Clear(TI2cMem*); + +//!Инициализатор по умолчанию +#define I2CMEM_DEFAULTS { .init = I2CMEM_Init, \ + .write = I2CMEM_Write,\ + .read = I2CMEM_Read,\ + .clearMem = I2CMEM_Clear,\ + } + +extern TI2cMem i2cMem; + +#endif /* INCLUDE_V_I2CMEM_H_ */ diff --git a/Vsrc/CANOpenUDfuncs.c b/Vsrc/CANOpenUDfuncs.c index 4f12b2c..b00fead 100644 --- a/Vsrc/CANOpenUDfuncs.c +++ b/Vsrc/CANOpenUDfuncs.c @@ -102,18 +102,18 @@ void co_CAN2GpioInit() //С точки зрения драйвера CANOpen функции реализуют побайтовое чтение и запись из/в ЭнОЗУ void co_UserMemoryRead (const T_UserMemoryContext *p) { -// UserMem.MemStartAddr = p->MemStartAddr; -// UserMem.MCUStartAddr = p->MCUStartAddr; -// UserMem.data_length = p->data_length; -// UserMem.read(&UserMem); + UserMem.MemStartAddr = p->MemStartAddr; + UserMem.MCUStartAddr = p->MCUStartAddr; + UserMem.data_length = p->data_length; + UserMem.read(&UserMem); } void co_UserMemoryWrite (const T_UserMemoryContext *p) { -// UserMem.MemStartAddr = p->MemStartAddr; -// UserMem.MCUStartAddr = p->MCUStartAddr; -// UserMem.data_length = p->data_length; -// UserMem.write(&UserMem); + UserMem.MemStartAddr = p->MemStartAddr; + UserMem.MCUStartAddr = p->MCUStartAddr; + UserMem.data_length = p->data_length; + UserMem.write(&UserMem); } //********************************************************************************************************************************************************************************************************** diff --git a/Vsrc/SM_Sys.c b/Vsrc/SM_Sys.c index 4e69f2d..94fd746 100644 --- a/Vsrc/SM_Sys.c +++ b/Vsrc/SM_Sys.c @@ -46,7 +46,7 @@ void SM_Sys_Init(TSM_Sys *p) { #endif cmd.all = 0; drv_status.all = 0; - + UserMem.init(&UserMem); sm_net.init(&sm_net); //Сетевая часть adc.init(&adc); //Инициализация АЦП sm_prot.init(&sm_prot); //Защиты diff --git a/Vsrc/V_UserMemory.c b/Vsrc/V_UserMemory.c index 9d0cbdc..3626b49 100644 --- a/Vsrc/V_UserMemory.c +++ b/Vsrc/V_UserMemory.c @@ -14,17 +14,17 @@ limitations under the License. \file V_UserMemory.c - \brief Работа с пользовательской энергонезависимой памятью 1921BK01 (см. TUserMemory) + \brief Обёртка для I2C памяти \author Лашкевич М.М., Шпак Д.М. - \version v 1.0 18/12/2014 + \version v 1.0 10/08/2019 */ /** \addtogroup TUserMemory */ /*@{*/ -#include +#include "V_UserMemory.h" #include "DSP.h" - +#include "V_i2cMem.h" @@ -34,10 +34,7 @@ //! \memberof TUserMemory void USERMEMORY_Init(TUserMemory *p) { - I2C->CTL1_bit.ENABLE = 1; - I2C->CTL1_bit.SCLFRQ = 63; // Divider: 100 000 000 / (63 * 4) ~ 400 кГц - I2C->CTL3_bit.SCLFRQ = 0; // Divider - + i2cMem.init(&i2cMem); } @@ -61,7 +58,11 @@ void USERMEMORY_UpdateCurrentPage(TUserMemory *p, Uint16 spiaddr) //! \memberof TUserMemory void USERMEMORY_Write(TUserMemory *p) { - + i2cMem.DSPstartaddr = p->MCUStartAddr; + i2cMem.MEMstartaddr = p->MemStartAddr; + i2cMem.data_length = p->data_length; + i2cMem.write(&i2cMem); + p->receivedCode = i2cMem.LastErr; } @@ -74,7 +75,11 @@ void USERMEMORY_Write(TUserMemory *p) //! \memberof TUserMemory void USERMEMORY_Read(TUserMemory *p) { - + i2cMem.DSPstartaddr = p->MCUStartAddr; + i2cMem.MEMstartaddr = p->MemStartAddr; + i2cMem.data_length = p->data_length; + i2cMem.read(&i2cMem); + p->receivedCode = i2cMem.LastErr; } @@ -101,7 +106,7 @@ void USERMEMORY_ReadToCache(TUserMemory *p, int16 pageNum) //! \memberof TUserMemory void USERMEMORY_Full_Erase(TUserMemory *p){ - + i2cMem.clearMem(&i2cMem); } diff --git a/Vsrc/V_i2cMem.c b/Vsrc/V_i2cMem.c new file mode 100644 index 0000000..2693d7f --- /dev/null +++ b/Vsrc/V_i2cMem.c @@ -0,0 +1,365 @@ +/* + * V_i2cMem.c + * + * Created on: 15 авг. 2019 г. + * Author: Dmitry + */ + + +#include "main.h" +#include "V_i2cmem.h" +#define I2C_MEM_ERROR_OK 0 +#define I2C_MEM_ERROR_WRITE_HW_ERR 1 +#define I2C_MEM_ERROR_READ_HW_ERR 2 +#define I2C_MEM_ERROR_TIMEOUT 3 + +TI2cMem i2cMem = I2CMEM_DEFAULTS; + +// Функция ожидания выполнения команды +Uint16 i2c_waitIdle() { + Uint32 idle = 0; + while ((I2C->ST & I2C_ST_MODE_Msk) == I2C_ST_MODE_IDLE){ + idle++; + if (idle > 10000000) + return 1; + }; + + return 0; +} + +// Функция ждёт, пока закончится внутренний цикл записи в памяти +// Если должались, пока микросхема освободится, то на выходе из функции она будет в состоянии +// ожидания приёма внутреннего адреса (то есть её послан старт и адрес устройства с битом "Write") +Uint16 i2c_waitMemBusyAndSendAddWr () { + volatile Uint32 waitCycles = 0; + // Посылаем старт и ждём, пока он сделается + I2C->CTL0 = I2C_CTL0_START_Msk; + if (i2c_waitIdle() != 0) return I2C_MEM_ERROR_TIMEOUT; + + if ((I2C->ST & I2C_ST_MODE_Msk) != I2C_ST_MODE_STDONE) + return I2C_MEM_ERROR_TIMEOUT; + + + do { + // Послать адрес устройства + Write, подождать, пока передастся + I2C->SDA = 0b10100000; + I2C->CTL0 = I2C_CTL0_CLRST_Msk; + if (i2c_waitIdle() != 0) return I2C_MEM_ERROR_TIMEOUT; + + // Смотрим, что прислало устройство. Если прислало "4" - значит внутренний цикл записи + // окончен и можно ехать дальше. Возвращаем 0 + if ((I2C->ST & I2C_ST_MODE_Msk) != I2C_ST_MODE_MTADPA){ + // Иначе смотрим, который раз уже пытаемся дождаться ответа. Если слишком долго - уходим отсюда + waitCycles++; + if (waitCycles > 10000000) { + I2C->CTL0 = I2C_CTL0_STOP_Msk | I2C_CTL0_CLRST_Msk; + return I2C_MEM_ERROR_TIMEOUT; + } + + // Если не слишком долго - высылаем повторный старт + I2C->CTL0 = I2C_CTL0_START_Msk; + I2C->CTL0 |= I2C_CTL0_CLRST_Msk; + if (i2c_waitIdle() != 0) return I2C_MEM_ERROR_TIMEOUT; + + if ((I2C->ST & I2C_ST_MODE_Msk) != I2C_ST_MODE_RSDONE) + return I2C_MEM_ERROR_TIMEOUT; + } + } while ((I2C->ST & I2C_ST_MODE_Msk) != I2C_ST_MODE_MTADPA); + + return I2C_MEM_ERROR_OK; +} + + +// Инит/переинит записи массива, который надо вызывать при достижении границы страницы (64 байта) +Uint16 i2c_initWriteArray (Uint16 address) { + Uint16 retVal; + // Ждём, пока память память закончин внутреннее сохранение + retVal = i2c_waitMemBusyAndSendAddWr(); + if (retVal != I2C_MEM_ERROR_OK) + return retVal; + + // Страший байт адреса 0x0000____ + I2C->SDA = (address >> 8) & 0xFF; + I2C->CTL0 = I2C_CTL0_CLRST_Msk; + if (i2c_waitIdle() != 0) return I2C_MEM_ERROR_TIMEOUT; + + // Если не квитирован - ошибка + if ((I2C->ST & I2C_ST_MODE_Msk) != I2C_ST_MODE_MTDAPA) + return I2C_MEM_ERROR_WRITE_HW_ERR; + + // Младший байт адреса 0x____0000 + I2C->SDA = (address >> 0) & 0xFF; + I2C->CTL0 = I2C_CTL0_CLRST_Msk; + if (i2c_waitIdle() != 0) return I2C_MEM_ERROR_TIMEOUT; + + // Если не квитирован - ошибка + if ((I2C->ST & I2C_ST_MODE_Msk) != I2C_ST_MODE_MTDAPA) + return I2C_MEM_ERROR_WRITE_HW_ERR; + + // Всё хорошо + return I2C_MEM_ERROR_OK; +} + +// Запись массива +Uint16 i2c_writeArray(Uint16 address, Uint16 *dataPtr_u16, Uint16 length_u8) { + // Тут внутри проще работать с байтами + Uint8* dataPtr_u8 = (Uint8*)dataPtr_u16; + + i2c_initWriteArray(address); + + // Поехали данные + while (length_u8 > 0) { + // Данные + I2C->SDA = *dataPtr_u8; + I2C->CTL0 = I2C_CTL0_CLRST_Msk; + if (i2c_waitIdle() != 0) return I2C_MEM_ERROR_TIMEOUT; + + // Если не квитирован - ошибка + if ((I2C->ST & I2C_ST_MODE_Msk) != I2C_ST_MODE_MTDAPA) + return I2C_MEM_ERROR_WRITE_HW_ERR; + + // Смотрим, не дошли ли до конца страницы внутри памяти/ + // Если дошли - надо сделать стоп и подождать, пока данные пропишутся + length_u8--; + dataPtr_u8++; + address++; + if ((address & 0x3F) == 0) { + // Формируем стоп и перезапускаем записывалку на новый адрес + I2C->CTL0 = I2C_CTL0_STOP_Msk; + I2C->CTL0 |= I2C_CTL0_CLRST_Msk; + i2c_initWriteArray(address); + } + } + + // Закончили - формируем стоп + I2C->CTL0 = I2C_CTL0_STOP_Msk; + I2C->CTL0 |= I2C_CTL0_CLRST_Msk; + return I2C_MEM_ERROR_OK; +} + +// Чтение массива 16-разрядных слов +Uint16 i2c_readArray(Uint16 address, Uint16* readDataPtr_u16, Uint16 length_u8){ + // Тут внутри проще работать с байтами + Uint8* readDataPtr_u8 = (Uint8*)readDataPtr_u16; + + Uint16 retVal; + + // Ждём, пока память память закончин внутреннее сохранение + retVal = i2c_waitMemBusyAndSendAddWr(); + if (retVal != I2C_MEM_ERROR_OK) + return retVal; + + // Страший байт адреса 0x0000____ + I2C->SDA = (address >> 8) & 0xFF; + I2C->CTL0 = I2C_CTL0_CLRST_Msk; + if (i2c_waitIdle() != 0) return I2C_MEM_ERROR_TIMEOUT; + + // Если не квитирован - ошибка + if ((I2C->ST & I2C_ST_MODE_Msk) != I2C_ST_MODE_MTDAPA) + return I2C_MEM_ERROR_READ_HW_ERR; + + // Младший байт адреса 0x____0000 + I2C->SDA = (address >> 0) & 0xFF; + I2C->CTL0 = I2C_CTL0_CLRST_Msk; + if (i2c_waitIdle() != 0) return I2C_MEM_ERROR_TIMEOUT; + + // Если не квитирован - ошибка + if ((I2C->ST & I2C_ST_MODE_Msk) != I2C_ST_MODE_MTDAPA) + return I2C_MEM_ERROR_READ_HW_ERR; + + // Повторный старт, чтобы перейти в режим мастера-приёмника + I2C->CTL0 = I2C_CTL0_START_Msk; + I2C->CTL0 |= I2C_CTL0_CLRST_Msk; + if (i2c_waitIdle() != 0) return I2C_MEM_ERROR_TIMEOUT; + + // Если режим неправильный - ошибка + if ((I2C->ST & I2C_ST_MODE_Msk) != I2C_ST_MODE_RSDONE) + return I2C_MEM_ERROR_READ_HW_ERR; + + // Адрес устройства + Read + I2C->SDA = 0b10100001; + I2C->CTL0 = I2C_CTL0_CLRST_Msk; + if (i2c_waitIdle() != 0) return I2C_MEM_ERROR_TIMEOUT; + + // Если передача адреса устройства не квитирована - ошибка + if ((I2C->ST & I2C_ST_MODE_Msk) != I2C_ST_MODE_MRADPA) + return I2C_MEM_ERROR_READ_HW_ERR; + + while (length_u8 > 1) { + // Принимаем байт, и квитируем + I2C->CTL0 = I2C_CTL0_CLRST_Msk; + if (i2c_waitIdle() != 0) return I2C_MEM_ERROR_TIMEOUT; + + // Если режим не стал правильным - ошибка + if ((I2C->ST & I2C_ST_MODE_Msk) != I2C_ST_MODE_MRDAPA) + return I2C_MEM_ERROR_READ_HW_ERR; + + *readDataPtr_u8 = I2C->SDA; + readDataPtr_u8++; + length_u8--; + } + + // Последний байт принимаем, но не квитируем + I2C->CTL0 = I2C_CTL0_ACK_Msk; // Reset + NACK + I2C->CTL0 |= I2C_CTL0_CLRST_Msk; + if (i2c_waitIdle() != 0) return I2C_MEM_ERROR_TIMEOUT; + + // Если режим не стал правильным - ошибка + if ((I2C->ST & I2C_ST_MODE_Msk) != I2C_ST_MODE_MRDANA) + return I2C_MEM_ERROR_READ_HW_ERR; + + *readDataPtr_u8 = I2C->SDA; + + // Формируем стоп + I2C->CTL0 = I2C_CTL0_STOP_Msk | I2C_CTL0_CLRST_Msk; + return I2C_MEM_ERROR_OK; +} + + +// Желаемая частота шины I2C в килогерцах +#define I2CMEM_FREQUENCY_KHZ 400 + +void I2CMEM_Init(TI2cMem*p){ + // Разрешаем работу 0 и 1 ножек порта А и переводим их в периферийный режим + GPIOA->DENSET |= 0x3; + GPIOA->ALTFUNCSET |= 0x3; + + // Разрешаем работу I2C модуля и ставим ему скорость + // Fi2c = Fcpu / (4 * SCLFRQ), а Fcpu для 035 = 100 МГц + I2C->CTL1 |= I2C_CTL1_ENABLE_Msk; + I2C->CTL1 |= (25000 / I2CMEM_FREQUENCY_KHZ) << I2C_CTL1_SCLFRQ_Pos; +} + +void I2CMEM_Write(TI2cMem*p){ + // Запись + p->LastErr = i2c_writeArray(p->MEMstartaddr, p->DSPstartaddr, p->data_length); +} + +void I2CMEM_Read(TI2cMem*p){ + // Чтение + p->LastErr = i2c_readArray(p->MEMstartaddr, p->DSPstartaddr, p->data_length); +} + +void I2CMEM_Clear(TI2cMem*p){ + // Стирание + Uint32 i = 0; + Uint16 ffArr[32]; + for (i = 0; i < 32; i++) { + ffArr[i] = 0xFFFF; + } + for (i = 0; i < EEPROM_MEM_LENGTH; i += 0x40){ + p->MEMstartaddr = i; + p->DSPstartaddr = ffArr; + p->data_length = 0x40; + + p->LastErr = i2c_writeArray(p->MEMstartaddr, p->DSPstartaddr, p->data_length); + if (p->LastErr != I2C_MEM_ERROR_OK) + return; + } +} + +/****** Депрекейтед, как говорится *******/ +//// Запись в память одного байта и "стоп" +//Uint16 i2c_writeSingleByteAndStop(Uint16 address, Uint8 data) +//{ +// Uint16 retVal; +// // Ждём, пока память память закончин внутреннее сохранение +// retVal = i2c_waitMemBusyAndSendAddWr(); +// if (retVal != I2C_MEM_ERROR_OK) +// return retVal; +// +// // Страший байт адреса 0x0000____ +// I2C->SDA = (address >> 8) & 0xFF; +// I2C->CTL0 = I2C_CTL0_CLRST_Msk; +// if (i2c_waitIdle() != 0) return I2C_MEM_ERROR_TIMEOUT; +// +// // Если не квитирован - ошибка +// if ((I2C->ST & I2C_ST_MODE_Msk) != I2C_ST_MODE_MTDAPA) +// return I2C_MEM_ERROR_WRITE_HW_ERR; +// +// // Младший байт адреса 0x____0000 +// I2C->SDA = (address >> 0) & 0xFF; +// I2C->CTL0 = I2C_CTL0_CLRST_Msk; +// if (i2c_waitIdle() != 0) return I2C_MEM_ERROR_TIMEOUT; +// +// // Если не квитирован - ошибка +// if ((I2C->ST & I2C_ST_MODE_Msk) != I2C_ST_MODE_MTDAPA) +// return I2C_MEM_ERROR_WRITE_HW_ERR; +// +// // Данные +// I2C->SDA = data; +// I2C->CTL0 = I2C_CTL0_CLRST_Msk; +// if (i2c_waitIdle() != 0) return I2C_MEM_ERROR_TIMEOUT; +// +// // Если не квитирован - ошибка +// if ((I2C->ST & I2C_ST_MODE_Msk) != I2C_ST_MODE_MTDAPA) +// return I2C_MEM_ERROR_WRITE_HW_ERR; +// +// // Формируем стоп +// I2C->CTL0 = I2C_CTL0_STOP_Msk; +// I2C->CTL0 |= I2C_CTL0_CLRST_Msk; +// return I2C_MEM_ERROR_OK; +//} +// +// +//// Чтение одного байта и стоп +//Uint8 i2c_readSingleByteAndStop(Uint16 address, Uint16* readData) +//{ +// Uint16 retVal; +// +// // Ждём, пока память память закончин внутреннее сохранение +// retVal = i2c_waitMemBusyAndSendAddWr(); +// if (retVal != I2C_MEM_ERROR_OK) +// return retVal; +// +// // Страший байт адреса 0x0000____ +// I2C->SDA = (address >> 8) & 0xFF; +// I2C->CTL0 = I2C_CTL0_CLRST_Msk; +// if (i2c_waitIdle() != 0) return I2C_MEM_ERROR_TIMEOUT; +// +// // Если не квитирован - ошибка +// if ((I2C->ST & I2C_ST_MODE_Msk) != I2C_ST_MODE_MTDAPA) +// return I2C_MEM_ERROR_READ_HW_ERR; +// +// // Младший байт адреса 0x____0000 +// I2C->SDA = (address >> 0) & 0xFF; +// I2C->CTL0 = I2C_CTL0_CLRST_Msk; +// if (i2c_waitIdle() != 0) return I2C_MEM_ERROR_TIMEOUT; +// +// // Если не квитирован - ошибка +// if ((I2C->ST & I2C_ST_MODE_Msk) != I2C_ST_MODE_MTDAPA) +// return I2C_MEM_ERROR_READ_HW_ERR; +// +// // Повторный старт, чтобы перейти в режим мастера-приёмника +// I2C->CTL0 = I2C_CTL0_START_Msk; +// I2C->CTL0 |= I2C_CTL0_CLRST_Msk; +// if (i2c_waitIdle() != 0) return I2C_MEM_ERROR_TIMEOUT; +// +// // Если режим неправильный - ошибка +// if ((I2C->ST & I2C_ST_MODE_Msk) != I2C_ST_MODE_RSDONE) +// return I2C_MEM_ERROR_READ_HW_ERR; +// +// // Адрес устройства + Read +// I2C->SDA = 0b10100001; +// I2C->CTL0 = I2C_CTL0_CLRST_Msk; +// if (i2c_waitIdle() != 0) return I2C_MEM_ERROR_TIMEOUT; +// +// // Если передача адреса устройства не квитирована - ошибка +// if ((I2C->ST & I2C_ST_MODE_Msk) != I2C_ST_MODE_MRADPA) +// return I2C_MEM_ERROR_READ_HW_ERR; +// +// // Принимаем байт, но не квитируем +// I2C->CTL0 = I2C_CTL0_ACK_Msk; // Reset + NACK +// I2C->CTL0 |= I2C_CTL0_CLRST_Msk; +// if (i2c_waitIdle() != 0) return I2C_MEM_ERROR_TIMEOUT; +// +// // Если режим не стал правильным - ошибка +// if ((I2C->ST & I2C_ST_MODE_Msk) != I2C_ST_MODE_MRDANA) +// return I2C_MEM_ERROR_READ_HW_ERR; +// +// *readData = I2C->SDA; +// // Формируем стоп +// I2C->CTL0 = I2C_CTL0_STOP_Msk | I2C_CTL0_CLRST_Msk; +// +// return I2C_MEM_ERROR_OK; +//}