290 lines
9.6 KiB
C
290 lines
9.6 KiB
C
/*!
|
|
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"
|
|
#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;
|
|
|
|
// Æåëàåìàÿ ÷àñòîòà øèíû 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;
|
|
};
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
// Ôóíêöèÿ æä¸ò, ïîêà çàêîí÷èòñÿ âíóòðåííèé öèêë çàïèñè â ìèêðîñõåìå ïàìÿòè.
|
|
// Ïîêà öèêë èä¸ò, ìèêðîñõåìà íå êâèòèðóåò îòïðàâëåííûé åé áàéò ñ ñîáñòâåííûì àäðåñîì è êîìàíäîé "Write"
|
|
// Åñëè äîëæàëèñü, ïîêà ìèêðîñõåìà îñâîáîäèòñÿ, òî íà âûõîäå èç ôóíêöèè îíà áóäåò â ñîñòîÿíèè
|
|
// îæèäàíèÿ ïðè¸ìà âíóòðåííåãî àäðåñà (òî åñòü å¸ ïîñëàí ñòàðò è àäðåñ óñòðîéñòâà ñ áèòîì "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 è GPIO, ê êîòîðûì ïîäêëþ÷åíà ïàìÿòü
|
|
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;
|
|
}
|
|
|
|
// Çàáèâàåì êàæäóþ ñòðàíèöó 0xFF
|
|
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;
|
|
}
|
|
}
|
|
/*@}*/
|