📄 hardwareio.c
字号:
/************************************************************************
*
* Copyright(c) 2004 ItoM BV
* All Rights Reserved.
*
* LV2400x evaluation kit: Take care of shadowing LV2400x registers
* File name: HardwareIo.c
* Hardware platform for 3-wire chip
* These functions are low level IO and system specific.
*
*************************************************************************/
#include <stdio.h>
#include "common.h"
#include "Lv24Ekit.h"
#ifdef USE_PRESET
#include "LcFls.h"
_rom BYTE gFlsRom[128] _at(0x00f700); // user' setting area in LC87F1564 flash
#endif //USE_PRESET
/* ************************************************************************************************
*
* Function: Init3wHardwareIo
*
* Authors: Hung van Le
* Purpose: Configure the hardware GPIO for for 3-wire usage.
* Input: Nothing
* Output: Nothing
* Comments: - The GPIO is configured as follows:
* NR_W is output of the uC, level is low (put 3W-device in read mode)
* CLOCK is output of the uC, level is high
* DATA is input of the uC
* - Interrupt is assigned to DATA-pin as system 3W-interrupt
* - Disable system 3W-interrupt
*
* ************************************************************************************************
* Copyright (c) 2004. Semiconductor Ideas to the Market (ItoM) B.V. All rights reserved.
* ************************************************************************************************ */
void Init3wHardwareIo(void)
{
// Config the GPIO
I3W_DIRPORT = (BYTE)(I3W_CLK_PIN_BM|
//I3W_DATA_PIN_BM|
I3W_NRW_PIN_BM|
I3W2_CLK_PIN_BM|
//I3W2_DATA_PIN_BM|
I3W2_NRW_PIN_BM); // All 3-wires pins are output except data pins, RDS pins are input
// Driving the GPIO to default level
I3W_PORT = I3W2_CLK_PIN_BM; // Clock is high, other pins are low (Read 3-wire mode)
// Assign system interrupt to GPIO
_I45SL = 0x80; // INT5(1Bh) at P26 (3-wire 1 DATA-pin), INT4(13h) at P20 (ext. RDS clock pin)
//_I45SL = 0x88; // INT5(1Bh) at P26 (3-wire 1 DATA-pin), INT4(13h) at P22 (3-wire 2 DATA-pin)
// Default is disabling 3W-interrupt
_I45CR = 0x00; // Disable INT4/INT5
} // End Init3wHardwareIo
/* ************************************************************************************************
*
* Function: IoWrite3W
*
* Authors: Hung van Le
* Purpose: Write 16 bit data to 3W-device
* Input: byLow: low byte of the data
* byHigh: high byte of the data
* Output: Nothing
* Global: None.
* Comments: - The LSB of the low byte will be written first
* - This function uses DGT4-protocol (CLOCK is default high)
*
* ************************************************************************************************
* Copyright (c) 2004. Semiconductor Ideas to the Market (ItoM) B.V. All rights reserved.
* ************************************************************************************************ */
void IoWrite3W(BYTE byLow, BYTE byHigh)
{
// Prepare the 3-wire bus for writing
_putbit(1, I3W_PORT, I3W_NRW_PIN); // nRW line high for writing
_putbit(1, I3W_DIRPORT, I3W_DATA_PIN); // Program DATA PIN to output
// Perfrom the 3W-write
IoWriteByte3W(byLow); // Write low byte
IoWriteByte3W(byHigh); // Write high byte
// Let the device latch data
_putbit(0, I3W_DIRPORT, I3W_DATA_PIN); // Change DATA PIN to input mode
_putbit(0, I3W_PORT, I3W_NRW_PIN); // nRW line low for latching data
} // End IoWrite3W
/* ************************************************************************************************
*
* Function: IoRead3W
*
* Authors: Hung van Le
* Purpose: Read 8 bit data from 3W-device
* Input: byReg: 8 bit data to be sent before the read (usually the register address for the read)
* Output: The read data byte
* Comments: - The LSB will be read first
* - This function uses DGT4-protocol (CLOCK is default high)
*
* ************************************************************************************************
* Copyright (c) 2004. Semiconductor Ideas to the Market (ItoM) B.V. All rights reserved.
* ************************************************************************************************ */
BYTE IoRead3W(BYTE byReg)
{
BYTE byBitCnt;
BYTE byData;
_putbit(1, I3W_PORT, I3W_NRW_PIN); // nRW line high for writing
_putbit(1, I3W_DIRPORT, I3W_DATA_PIN); // Program DATA PIN to output
// Write the register offset
IoWriteByte3W(byReg);
//_putbit(0, I3W_PORT, I3W_CLK_PIN); // Clock low by exit for V3, leave it high for V4
_putbit(0, I3W_DIRPORT, I3W_DATA_PIN); // Change DATA PIN to input mode
_putbit(0, I3W_PORT, I3W_NRW_PIN); // nRW line low for latching data
// Read the 8 bits data (LSB is read first)
byData = 0;
for (byBitCnt=0; byBitCnt<8; byBitCnt++)
{
_putbit(0, I3W_PORT, I3W_CLK_PIN); // Clock low -> The chip shifts its data out
byData>>=1; // Make room for next bit (the first shift is dummy!)
if ( _getbit(I3W_PORT, I3W_DATA_PIN ) )
byData |= 0x80;
_putbit(1, I3W_PORT, I3W_CLK_PIN); // Clock high
}
// Return the read data
return(byData);
} // End IoRead3W
/* ************************************************************************************************
*
* Function: IoWriteByte3W
*
* Authors: Hung van Le
* Purpose: Generate clock to send 8 bit data to 3W-device
* Input: byData: 8 bit data to be sent
* Output: Nothing
* Comments: - This function is meant for internal usage (to be called by IoWrite3W or IoRead3W)
*
* ************************************************************************************************
* Copyright (c) 2004. Semiconductor Ideas to the Market (ItoM) B.V. All rights reserved.
* ************************************************************************************************ */
void IoWriteByte3W(BYTE byData)
{
// Write 1 byte to the 3-wire device (LSB is written first)
// Caller must prepare the bus for write mode before invoke this function
BYTE byBitCnt;
// Number of data bit
byBitCnt = 8;
// Write the data to the chip: LSB first
while (byBitCnt)
{
_putbit(0, I3W_PORT, I3W_CLK_PIN); // Clock low
if (byData & 1)
_putbit(1, I3W_PORT, I3W_DATA_PIN); // Drive data pin high
else
_putbit(0, I3W_PORT, I3W_DATA_PIN); // Drive data pin low
_putbit(1, I3W_PORT, I3W_CLK_PIN); // Clock high
byData >>=1; // Next bit
byBitCnt--;
}
} // End IoWriteByte3W
/* ************************************************************************************************
*
* Function: Pulse3wNRW
*
* Authors: Hung van Le
* Purpose: Pulse the 3W-NRW signal for specified time. Return the real time in us
* Input: wStart: the pattern to send to the 3W-bus to start the pulse period
* wStop: the stop pattern to send to the 3W-bus after the period is expired
* dwTimeUs: time in us to pulse the NRW-signal
* Output: The actual pulse time in us
* Global: g_bySwFlag1 (W): clear/set SF1_PULSE3W_BUSY flag to mark pulse period
* Comments: - This function is meant for measuring frequency of the 3W chip: the start pattern will start the counter 1
* in the 3W-chip. When the pulse period expires, the NRW goes high which stops the counter 1 of the 3W-chip.
* The stop pattern disables this counter (freezing the counter value). With the counter1 value and the pulse
* period, the frequency can be calculated
* - This function is not required when the external clock is used by frequency measurement
*
* ************************************************************************************************
* Copyright (c) 2004. Semiconductor Ideas to the Market (ItoM) B.V. All rights reserved.
* ************************************************************************************************ */
DWORD Pulse3wNRW(WORD wStart, WORD wStop, DWORD dwTimeUs)
{
BYTE byTmp;
WORD wInitialCnt, wExtraCnt;
// Prepare timer 0 for measuring
wInitialCnt = ArmTimer0ForMsr(dwTimeUs);
// No interrupt between starting the 2 counters
byTmp = _IE; // Save the org. interrupt state
_IE = 0x00;
// Start measuring.
#ifdef USE_USB
// We use UsbWrite (support both DGT3/DGT4) to support both USB-mode and stand alone mode
UsbWrite3wV3V4(LSB(wStart), MSB(wStart)); // Write the start pattern
#else // USE_USB
// For stand alone mode, using IoWrite3W (only support DGT4)
IoWrite3W(LSB(wStart), MSB(wStart));
#endif //USE_USB
// Start timer 0 of LC8715xx (in mode 2)
_T0CNT = 0xE4; // Set T0HRUN, T0LRUN, T0LONG, T0HIE bits (enable match TOHR interrupt)
// Enable interrupt
_IE = 0x80;
// Wait until the timer expires - TODO: add time-out check
while (g_bySwFlag1 & SF1_PULSE3W_BUSY);
// No interrupt between stopping the 2 counters
_IE = 0x00;
// Timer expired. Let LV2400x enter write mode to stop its counter
_putbit(1, I3W_PORT, I3W_NRW_PIN); // Drive NR_W high (Write mode)
// We can not read the T0L/T0H because the LC8715xx clears these register when it stops.
// So select extern input to freeze T0L/T0H for reading it. Be sure that nothing is
// toggling the time 0 extern input !!!
//_putbit(1, _T0CNT, _T0LEXT); // Select extern input for timer 0
_putbit(1, _T0CNT, 4); // Select extern input for timer 0 (stop the timer)
// Change DATA-pin to output: place here to avoid software overhead between stopping
// LV2400x counter and stopping LC8715xx timer
_putbit(1, I3W_DIRPORT, I3W_DATA_PIN);
// Restore system interrupt
_IE = byTmp;
// Fetch the extra count
wExtraCnt = _T0H; // Fetch high byte of timer 0
wExtraCnt <<= 8;
wExtraCnt |= _T0L; // Fetch low byte of timer 0
// Disable timer 0 - clear interrupt
_T0CNT = 0x00;
// Write the stop pattern
#ifdef USE_USB
// We use UsbWrite (support both DGT3/DGT4) to support both USB-mode and stand alone mode
UsbWrite3wV3V4(LSB(wStop), MSB(wStop)); // Write the start pattern
#else // USE_USB
// For stand alone mode, using IoWrite3W (only support DGT4)
IoWrite3W(LSB(wStop), MSB(wStop));
#endif //USE_USB
// Determine the real measuring time (in us)
dwTimeUs = wInitialCnt + wExtraCnt;
byTmp = _T0PRR; // Fetch prescaler
byTmp += 1; // Number of Tcyc is prescaler+1
dwTimeUs *= byTmp; // dwTimeUs = number of Tcyc expired
dwTimeUs += 12; // Compensate the push/pop/ret of WriteReg between the last WriteReg and enable timer 0 (12 cycle)
dwTimeUs *= LC8715XX_TCYC_NS; // dwTimeUs = time in ns
dwTimeUs /= 1000; // convert ns to us
return(dwTimeUs);
} // End Pulse3wNRW
/* ************************************************************************************************
*
* Function: ArmTimer0ForMsr
*
* Authors: Hung van Le
* Purpose: Calculate value of _T0PRR, _T0LR and _T0HR to work with timer 0 of LC87F1564
* Input: dwTimeUs: time required for the timer in us
* Output: The prescaler is written to _T0PRR
* The expected count value is written to _T0LR and _T0HR
* Return the expected count
* Global: g_bySwFlag1 (W): set SF1_PULSE3W_BUSY flag
* Comments: - This function can be inline of function Pulse3wNRW.
*
* ************************************************************************************************
* Copyright (c) 2004. Semiconductor Ideas to the Market (ItoM) B.V. All rights reserved.
* ************************************************************************************************ */
WORD ArmTimer0ForMsr(DWORD dwTimeUs)
{
DWORD dwTmp, dwCnt;
BYTE byPrr;
switch (dwTimeUs)
{
#ifdef CF8MHZ
// First do look up for familiar values (t = byPrr*375ns*Cnt)
// PRR Clock Count Time(ms)
// 2 750ns 10666 8ms
// 2 750ns 42666 32ms
// 3 1125ns 56888 64ms
// 5 1875ns 53333 100ms
// Reduce time due to software overhead
// 2 750ns 8000 6ms
// 2 750ns 40000 30ms
// 4 1500ns 40000 60ms
// 5 1875ns 51200 96ms
case LV_MSR_TIME_8ms:
byPrr = 2;
dwCnt = 8000; // should be 10666
break;
case LV_MSR_TIME_32ms:
byPrr = 2;
dwCnt = 40000; // should be 42666
break;
case LV_MSR_TIME_64ms:
byPrr = 4; // should be 3
dwCnt = 40000; // was 56888
break;
case LV_MSR_TIME_100ms:
byPrr = 5;
dwCnt = 51200; // should be 53333
break;
#endif //CF8MHZ
#ifdef CF12MHZ
// First do look up for familiar values (t = byPrr*375ns*Cnt)
// PRR Clock Count Time(ms)
// 2 500ns 16000 8ms
// 2 500ns 64000 32ms
// 4 1000ns 64000 64ms
// 7 1750ns 57142 100ms
// Reduce time due to software overhead
// 2 500ns 12000 6ms
// 2 500ns 60000 30ms
// 4 1000ns 60000 60ms
// 7 1750ns 54857 96ms
case LV_MSR_TIME_8ms:
byPrr = 2;
dwCnt = 12000; // should be 16000
break;
case LV_MSR_TIME_32ms:
byPrr = 2;
dwCnt = 60000; // should be 64000
break;
case LV_MSR_TIME_64ms:
byPrr = 4;
dwCnt = 60000; // should be 64000
break;
case LV_MSR_TIME_100ms:
byPrr = 5;
dwCnt = 54857; // should 57142
break;
#endif //CF12MHZ
// Remaining values: Calulate the setting for time 0
default:
// Find out the approriate value for T0PRR, T0LR, T0HR
dwTimeUs *= 1000; // Convert us to ns
for (byPrr=2; byPrr<20; byPrr++)
{
dwTmp = byPrr;
dwTmp *= LC8715XX_TCYC_NS; // Cycle time in ns
dwCnt = dwTimeUs/dwTmp; // Count value
if (dwCnt < 0xFFFF)
break; // Break for-loop: Find approriate value
}
break; // break case
} // EndSwitch
// Prepare timer 0 of LC8715xx
_T0CNT = 0x10; // Set T0LONG bit for 16 bit timer, stop counter, clear interrupt
_T0PRR = (byPrr-1); // Prescaler match register (T0PRR)
_T0LR = LSB(dwCnt); // data match register T0LR (count low)
_T0HR = MSB(dwCnt); // data match register T0HR (count high)
g_bySwFlag1 |= SF1_PULSE3W_BUSY; // Mark measuring in progress
return((WORD)dwCnt);
} // End ArmTimer0ForMsr
/* ************************************************************************************************
*
* Function: HandleTimer0Done
*
* Authors: Hung van Le
* Purpose: Invoked by timer 0 interrupt when the timer period expired
* Input: Nothing
* Output: Nothing
* Global: g_bySwFlag1 (W): Clear SF1_PULSE3W_BUSY flag
* Comments: This function is part of timer 0 interrupt handler
*
* ************************************************************************************************
* Copyright (c) 2004. Semiconductor Ideas to the Market (ItoM) B.V. All rights reserved.
* ************************************************************************************************ */
void HandleTimer0Done(void)
{
// Mark timer 0 expired (clear counter busy flag)
g_bySwFlag1 &= (BYTE)(~SF1_PULSE3W_BUSY);
} // End HandleTimer0Done
/* ************************************************************************************************
*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -