From 7e38106ce240155a56c027faaab139709f60c28c Mon Sep 17 00:00:00 2001 From: Dmitry Shpak Date: Fri, 16 Aug 2019 11:38:16 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9E=D1=84=D0=BE=D1=80=D0=BC=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D1=8B=20=D0=BA=D0=BE=D0=BC=D0=BC=D0=B5=D0=BD=D1=82=D0=B0?= =?UTF-8?q?=D1=80=D0=B8=D0=B8=20=D0=B2=20I2C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .settings/language.settings.xml | 4 +- Vinclude/V_i2cMem.h | 33 ++++-- Vsrc/V_i2cMem.c | 180 +++++++++----------------------- 3 files changed, 79 insertions(+), 138 deletions(-) diff --git a/.settings/language.settings.xml b/.settings/language.settings.xml index 2540c60..0b7af04 100644 --- a/.settings/language.settings.xml +++ b/.settings/language.settings.xml @@ -5,7 +5,7 @@ - + @@ -16,7 +16,7 @@ - + diff --git a/Vinclude/V_i2cMem.h b/Vinclude/V_i2cMem.h index e72bc7b..f63c12d 100644 --- a/Vinclude/V_i2cMem.h +++ b/Vinclude/V_i2cMem.h @@ -1,14 +1,31 @@ -/* - * V_i2cMem.h - * - * Created on: 15 авг. 2019 г. - * Author: Dmitry - */ +/*! + Copyright 2019 АО "НИИЭТ" и ООО "НПФ ВЕКТОР" + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + \file v_i2cMem.h + \brief Драйвер для работы с микросхемой флеш памяти 24LC256 по + интерфейсу I2C + \author ООО "НПФ Вектор". http://motorcontrol.ru + \version v 1.0 10/08/2019 + + \addtogroup v_i2cMem +@{ +*/ #ifndef INCLUDE_V_I2CMEM_H_ #define INCLUDE_V_I2CMEM_H_ -#define EEPROM_MEM_LENGTH 32768 //длина флешки в байтах (256 кбит) +#define EEPROM_MEM_LENGTH 32768 // Размер памяти в байтах (256 кбит) struct SI2cMem; typedef volatile struct SI2cMem TI2cMem; @@ -16,7 +33,7 @@ typedef volatile struct SI2cMem TI2cMem; struct SI2cMem { Uint16 MEMstartaddr; //! Адрес на flash Uint16 data_length; //! Длина данных в байтах - Uint16 *DSPstartaddr; //! Адрес на массив с данными + Uint16 *DSPstartaddr; //! Адрес на массив с данными в контроллере Uint16 LastErr; //! Код ошибки (если возникла) void (*init)(TI2cMem*); void (*write)(TI2cMem*); diff --git a/Vsrc/V_i2cMem.c b/Vsrc/V_i2cMem.c index 2693d7f..f108954 100644 --- a/Vsrc/V_i2cMem.c +++ b/Vsrc/V_i2cMem.c @@ -1,10 +1,27 @@ -/* - * V_i2cMem.c - * - * Created on: 15 авг. 2019 г. - * Author: Dmitry - */ +/*! + Copyright 2019 АО "НИИЭТ" и ООО "НПФ ВЕКТОР" + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + \file v_i2cMem.c + \brief Драйвер для работы с микросхемой флеш памяти 24LC256 по + интерфейсу I2C + \author ООО "НПФ Вектор". http://motorcontrol.ru + \version v 1.0 10/08/2019 + + \addtogroup v_i2cMem +@{ +*/ #include "main.h" #include "V_i2cmem.h" @@ -15,11 +32,17 @@ TI2cMem i2cMem = I2CMEM_DEFAULTS; -// Функция ожидания выполнения команды +// Желаемая частота шины I2C в килогерцах +#define I2CMEM_FREQUENCY_KHZ 400 + +// Функция ожидания выполнения команды модулем I2C +// Просто ждёт, пока модуль выйдет из состояния "IDLE" Uint16 i2c_waitIdle() { Uint32 idle = 0; + while ((I2C->ST & I2C_ST_MODE_Msk) == I2C_ST_MODE_IDLE){ idle++; + // Если ожидание слишком долгое - выдать ошибку if (idle > 10000000) return 1; }; @@ -27,7 +50,9 @@ Uint16 i2c_waitIdle() { return 0; } -// Функция ждёт, пока закончится внутренний цикл записи в памяти + +// Функция ждёт, пока закончится внутренний цикл записи в микросхеме памяти. +// Пока цикл идёт, микросхема не квитирует отправленный ей байт с собственным адресом и командой "Write" // Если должались, пока микросхема освободится, то на выходе из функции она будет в состоянии // ожидания приёма внутреннего адреса (то есть её послан старт и адрес устройства с битом "Write") Uint16 i2c_waitMemBusyAndSendAddWr () { @@ -66,11 +91,13 @@ Uint16 i2c_waitMemBusyAndSendAddWr () { } } while ((I2C->ST & I2C_ST_MODE_Msk) != I2C_ST_MODE_MTADPA); + // Дошли до сюда - всё хорошо return I2C_MEM_ERROR_OK; } - -// Инит/переинит записи массива, который надо вызывать при достижении границы страницы (64 байта) +// Вспомогательная функция для блочной записи данных в памяти. +// Осуществляет инит/переинит записи массива, который надо вызывать +// при достижении границы страницы (64 байта) внутри памяти. Uint16 i2c_initWriteArray (Uint16 address) { Uint16 retVal; // Ждём, пока память память закончин внутреннее сохранение @@ -100,16 +127,16 @@ Uint16 i2c_initWriteArray (Uint16 address) { 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; @@ -118,11 +145,12 @@ Uint16 i2c_writeArray(Uint16 address, Uint16 *dataPtr_u16, Uint16 length_u8) { 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; @@ -144,7 +172,7 @@ Uint16 i2c_readArray(Uint16 address, Uint16* readDataPtr_u16, Uint16 length_u8){ Uint16 retVal; - // Ждём, пока память память закончин внутреннее сохранение + // Ждём, пока память память закончит внутреннее сохранение retVal = i2c_waitMemBusyAndSendAddWr(); if (retVal != I2C_MEM_ERROR_OK) return retVal; @@ -185,8 +213,8 @@ Uint16 i2c_readArray(Uint16 address, Uint16* readDataPtr_u16, Uint16 length_u8){ 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; @@ -216,9 +244,8 @@ Uint16 i2c_readArray(Uint16 address, Uint16* readDataPtr_u16, Uint16 length_u8){ } -// Желаемая частота шины I2C в килогерцах -#define I2CMEM_FREQUENCY_KHZ 400 +// Инит модуля I2C и GPIO, к которым подключена память void I2CMEM_Init(TI2cMem*p){ // Разрешаем работу 0 и 1 ножек порта А и переводим их в периферийный режим GPIOA->DENSET |= 0x3; @@ -230,23 +257,25 @@ void I2CMEM_Init(TI2cMem*p){ 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; } + + // Забиваем каждую страницу 0xFF for (i = 0; i < EEPROM_MEM_LENGTH; i += 0x40){ p->MEMstartaddr = i; p->DSPstartaddr = ffArr; @@ -257,109 +286,4 @@ void I2CMEM_Clear(TI2cMem*p){ 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; -//} +/*@}*/