📄 mbusman.cpp
字号:
#include "bastype.h"
#include "mcf5206.h"
//#include "systypes.h"
#include "syscfg.h"
#include "mbuspack.h"
#include "mbusman.h"
/**
* This module contains functions for MBUS operation, which including
* four MBUS chip's communication protocol, MCF5206 MBUS module
* initialization code, MBUS interrupt service routine.
*/
/**
* External varibales declare.
*/
extern MBusPackQueType gCAT24C021ReadPackQue;
extern MBusPackQueType gCAT24C021WritePackQue;
/**
* static variables define
*/
static MBusInfoType sMBusInfo = {
OPMODE_QUERY, // initialize to query mode.
0, // current packet processing finished.
0, // error count clear
0, // clear transferFail
RTC_NO // No Real-Time Clock
};
/**
* The following static variables was used for processing a full data transfer
*/
// Commands to be processed
static UCHAR sMBusCmds[600];
// current command to be processed
static INT16 sCurrentCmd;
// where is the data to be transmitted
static UCHAR *sTransmitPtr;
// where is the data received to be saved.
static UCHAR *sReceivePtr;
// because all queue are processed in turning, so remember these queues
static MBusPackQueType *sMBusPackQues[PACKQUE_NUMBER] = {
&gCAT24C021ReadPackQue,
&gCAT24C021WritePackQue
};
// A DRAM memory map of EEPROM for calculating checkSum
static UCHAR sMemoryMap[EEPROM_SIZE];
static UCHAR sCheckSum;
/**
* Initialize MBUS module.
*/
VOID MBusInit(VOID)
{
INT32 i;
UCHAR status;
// Problem:
// The I2C bus is hanging. When the ColdFire is reset during
// an access to an I2C slave device the MBB bit in the MBSR
// register is set and we can't communicate with the peripheral
// device. What do we do to re-start communications?
// Solution:
// During the initialization of the M-Bus module, the user should
// check the MBB bit of the MBSR register. If the MBB bit is set
// when the M-Bus module is enabled, then the follow code sequence
// should be executed before proceeding with your normal initialization
// code. This will issue a STOP command to the slave device which
// will then place it into the idle mode state as if it were just
// power cycled on.
// MBCR = $0
// MBCR = $A0
// dummy read of MBDR
// MBSR = $0
// MBCR = $0
*(UCHAR*)MBCR = 0;
*(UCHAR*)MBCR = 0xA0;
status = *(UCHAR*)MBDR;
for(i = 0; i < 10000; i ++)
;
*(UCHAR*)MBSR = 0;
*(UCHAR*)MBCR = 0;
// Reset MBUS.
*(UCHAR*)MBCR = 0;
// MBUS interrupt level and priority define:
// 100 011 00: autovector and level 3, priority 0
// *(UCHAR*)MBUS_ICR = 0x8c;
// SCL freqency setting: 51.6096M / 640 = 80640.
// Note: the index of prescalar value 640 is 0x38.
*(UCHAR*)MFDR = 0x38;
// The slave address of MBUS module in MCF5206 is 0x11 when it addressed
// as a slave. Can it be deleted.
*(UCHAR*)MADR = 0x11;
// enable MBUS, but interrupt was disabled
*(UCHAR*)MBCR = 0x80;
// enable MBUS and its interrupt
//*(UCHAR*)MBCR = 0xc0;
// Set operation mode to query.
sMBusInfo.mode = OPMODE_QUERY;
sMBusInfo.currPackFinished = 1;
// generate stop signal
status = *(UCHAR*)MBCR;
status &= 0xd7;
*(UCHAR*)MBCR = status;
}
/**
* Mixed MBUS interrupt with other interrupt(using the same interrupt
* vector), Know the MBUS interrupt is occurred by inspecting MIF.
extern "C" VOID MBusMixedLisr(VOID)
{
// If MBUS operation in interrupt mode, call LISR
if ( OPMODE_INTERRUPT == sMBusInfo.mode)
Mbus_Lisr(0);
}
*/
/**
* MBus interrupt service routine
*/
extern "C" VOID Mbus_Lisr(int vector)
{
UCHAR status, ackNotDetected;
//clear MIF(M-Bus interrupt flag)
status = *(UCHAR*)MBSR;
// return if MIF is not set.
if (2 != (status&2) )
return;
status &= 0xfd;
*(UCHAR*)MBSR = status;
// No error detected.
ackNotDetected = 0;
sCurrentCmd ++;
// Check acknowledge signal when current command is not CMD_RECEIVE_STOP,
// because acknowledge signal will not be generated in the situation.
if (CMD_RECEIVE_STOP != sMBusCmds[sCurrentCmd])
{
if ( 1 == (status&1))
{
sMBusInfo.noAckError ++;
ackNotDetected = 1;
// cause system to generate stop signal
sMBusCmds[sCurrentCmd] = CMD_TRANSMIT_STOP;
}
}
switch (sMBusCmds[sCurrentCmd])
{
// normal transmit
case CMD_TRANSMIT:
*(UCHAR*)MBDR = *sTransmitPtr ++;
break;
// a stop after transmitting
case CMD_TRANSMIT_STOP:
status = *(UCHAR*)MBCR;
status &= 0xd7; // d7->df, why use d7? TXAK = 0?
*(UCHAR*)MBCR = status;
if( (1 == ackNotDetected) && (1 == RepeatTransfer()) )
{
// do nothing
}
else
{
// If work in query mode, don't check packet queue
if (OPMODE_QUERY == sMBusInfo.mode)
sMBusInfo.currPackFinished = 1;
/*
else
if (0 == ProcessNext() )
sMBusInfo.currPackFinished = 1;
*/
}
break;
// change to receive mode after transmitted
case CMD_TRANSMIT_RECEIVE:
// change to receive mode
status = *(UCHAR*)MBCR;
status &= 0xef;
*(UCHAR*)MBCR = status;
if (CMD_RECEIVE_STOP == sMBusCmds[sCurrentCmd+1])
{
// don't acknowledge it because it's the last byte to be received
status = *(UCHAR*)MBCR;
status |= 0x8;
*(UCHAR*)MBCR = status;
}
// Dummy read to generate clock signal
status = *(UCHAR*)MBDR;
break;
// restart then transmit
case CMD_RESTART_TRANSMIT:
// restart
status = *(UCHAR*)MBCR;
status |= 0x04;
*(UCHAR*)MBCR = status;
// then transmit
*(UCHAR*)MBDR = *sTransmitPtr ++;
break;
// receive with acknowledge
case CMD_RECEIVE_ACK:
*sReceivePtr ++ = *(UCHAR*)MBDR;
break;
// receive without acknowledge
case CMD_RECEIVE_NOACK:
// don't generate acknowledge signal
status = *(UCHAR*)MBCR;
status |= 0x08;
*(UCHAR*)MBCR = status;
*sReceivePtr ++ = *(UCHAR*)MBDR;
break;
// receive then stop
case CMD_RECEIVE_STOP:
// generate stop signal
status = *(UCHAR*)MBCR;
status &= 0xd7; // d7->df, why use d7? TXAK = 0?
*(UCHAR*)MBCR = status;
*sReceivePtr ++ = *(UCHAR*)MBDR;
// If work in query mode, don't check packet queue
if (OPMODE_QUERY == sMBusInfo.mode)
sMBusInfo.currPackFinished = 1;
/*
else
if (0 == ProcessNext() )
sMBusInfo.currPackFinished = 1;
*/
break;
default:
break;
}
}
/**
* Process next packet: check whether there is some packets that not been
* processed.
*
* @return 0 if not packet to be processed.
* @return 1 if there are packets to be processed.
*/
/*
static INT16 ProcessNext(VOID)
{
static INT16 currentQue;
MBusPackType *thePack = 0;
CHAR i;
// if MBUS is not free until function return, transfer stop
if (0 == WaitForMBusFree())
return 0;
// search a packQue that has packet to be processed.
for (i = 0; i < PACKQUE_NUMBER; i ++)
{
currentQue ++;
if (PACKQUE_NUMBER <= currentQue)
currentQue = 0;
if (1 == MBusPackQueGet(sMBusPackQues[currentQue], &thePack) )
break;
}
// if no packet to be processed, return
if (0 == thePack)
return 0;
// Remember the pack being transfered.
sMBusInfo.currPack = *thePack;
ConstructSequence(thePack);
StartTransfer();
return 1;
}
*/
/**
* Repeat transfer for given times.
* processed.
*
* @return 0 if repeat is not need or mbus is busy.
* @return 1 if repeat processed.
*/
static INT16 RepeatTransfer(VOID)
{
// if MBUS is not free until function return, transfer stop
if (0 == WaitForMBusFree())
return 0;
if (0 < sMBusInfo.currPack.repeatTimes)
{
sMBusInfo.currPack.repeatTimes --;
ConstructSequence(&sMBusInfo.currPack);
StartTransfer();
return 1;
}
else
{
sMBusInfo.transferFail ++;
return 0;
}
}
/**
* Construct command sequence according to the pack given,
* the command sequence will processed in MBus interrupt.
*
* @param pack the packet to be processed.
*/
static VOID ConstructSequence(MBusPackType *pack)
{
INT16 i, cmdNumber;
// The number of commands is 0
cmdNumber = 0;
// Commands are type of CMD_TRANSMIT at early.
for ( i = 0; i < pack->txLen1 - 1; i ++)
sMBusCmds[cmdNumber++] = CMD_TRANSMIT;
// If txLen2 is greater than 0, it means that there is a RESTART signal
// should insert here.
if (0 < pack->txLen2)
{
sMBusCmds[cmdNumber++] = CMD_RESTART_TRANSMIT;
// copy the other TRANSMIT command, remember here: the RESTART command
// was connected with a TRANSMIT command, so (pack->txLen2 - 1) is
// present here.
for ( i = 0; i < pack->txLen2 - 1; i ++)
sMBusCmds[cmdNumber++] = CMD_TRANSMIT;
}
// If want receive some characters.
if (0 < pack->rxLen)
{
// The last command is change mode to receive
sMBusCmds[cmdNumber++] = CMD_TRANSMIT_RECEIVE;
// If only receive one character, STOP after RECEIVE
if (1 == pack->rxLen)
sMBusCmds[cmdNumber++] = CMD_RECEIVE_STOP;
else
{
for ( i = 0; i < pack->rxLen - 2; i ++)
sMBusCmds[cmdNumber++] = CMD_RECEIVE_ACK;
// The second last command is CMD_RECEIVE_NOACK
sMBusCmds[cmdNumber++] = CMD_RECEIVE_NOACK;
// The last command is CMD_RECEIVE_STOP
sMBusCmds[cmdNumber++] = CMD_RECEIVE_STOP;
}
}
// Don't want receive any character, change the last command from
// TRANSMIT to TRANSMIT_STOP
else
sMBusCmds[cmdNumber++] = CMD_TRANSMIT_STOP;
sCurrentCmd = -1;
sTransmitPtr = &pack->txData[0];
sReceivePtr = pack->rxData;
}
/**
* Start a MBUS data transfer procedure.
*/
static VOID StartTransfer(VOID)
{
UCHAR status, data;
//clear MIF(M-Bus interrupt) flag
status = *(UCHAR*)MBSR;
status &= 0xfd;
*(UCHAR*)MBSR = status;
status = *(UCHAR*)MBCR;
// transmit mode selected
status |= 0x10;
*(UCHAR*)MBCR = status;
// master mode selected.
status |= 0x20;
*(UCHAR*)MBCR = status;
// BUG: if interrupt occurred after data being put into MBDR and
// sTransmitPtr has not been increased, the first byte will be
// transmitted for twice. MBUS will will be locked.
//*(UCHAR*)MBDR = *sTransmitPtr ++;
data = *sTransmitPtr ++;
*(UCHAR*)MBDR = data;
}
/**
* If MBUS is not busy, make it transfer another packet.
*/
/*
static VOID EnterInterrupt(VOID)
{
// return if operate in query mode
if (OPMODE_QUERY == sMBusInfo.mode)
return;
// Processing finished, start interrupt
if (1 == sMBusInfo.currPackFinished)
{
// Make the following code is used exclusively
sMBusInfo.currPackFinished = 0;
if (0 == ProcessNext() )
// It's impossible that program will go here, because there is new
// packet in the queue.
sMBusInfo.currPackFinished = 1;
}
}
*/
/**
* CAT24C021 initialize: Load the EEPROM to make a copy in DRAM and check the checkSum.
* this function must be called before any writing operation to CAT24C021
* with checkSum, or the check sum will be wrong.
*
* @return 1 load memoryMap and stored checkSum succeeded and checkSum is right
* 0 load memoryMap or stored checkSum failed
* 2 load memoryMap and stored checkSum succeeded but checkSum is wrong
*
CHAR CAT24C021Initialize(VOID)
{
// Load the memory map from CAT24C021
return CAT24C021LoadMemoryMap(sMemoryMap);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -