motorcontroldemo_035/Vsrc/V_i2cMem.c
2019-08-16 11:38:16 +03:00

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;
}
}
/*@}*/