mirror of
https://github.com/Gericom/libtwl.git
synced 2025-06-20 03:55:36 -04:00
167 lines
4.2 KiB
C
167 lines
4.2 KiB
C
#include <nds.h>
|
|
#include "libtwl/sio/sio.h"
|
|
#include "libtwl/sio/sioRtc.h"
|
|
|
|
// rtc setup/hold duration
|
|
#define RTC_WAIT_200NS 0
|
|
// rtc clock pulse duration
|
|
#define RTC_WAIT_1US 7
|
|
|
|
/// @brief Waits the given number of iterations of a loop
|
|
/// that takes 4 cycles per iteration.
|
|
/// @note Calling this method and returning takes at least 8 cycles.
|
|
/// As such the number of cycles is 8 + iterations * 4.
|
|
extern void rtc_waitByLoop(int iterations);
|
|
|
|
static inline void sendBit(u32 bit)
|
|
{
|
|
REG_RCNT1 = (REG_RCNT1 & ~(RCNT1_DATA_RTC_SIO | RCNT1_DATA_RTC_SCK)) | (bit ? RCNT1_DATA_RTC_SIO : 0);
|
|
rtc_waitByLoop(RTC_WAIT_1US);
|
|
REG_RCNT1 |= RCNT1_DATA_RTC_SCK;
|
|
rtc_waitByLoop(RTC_WAIT_1US);
|
|
}
|
|
|
|
static inline void sendByte(u32 byte)
|
|
{
|
|
// all rtc pins to output, CS high
|
|
sio_setRtcPins(
|
|
RCNT1_DIR_RTC_CS_OUTPUT | RCNT1_DIR_RTC_SCK_OUTPUT | RCNT1_DIR_RTC_SIO_OUTPUT,
|
|
RCNT1_DATA_RTC_CS);
|
|
for (u32 i = 0; i < 8; i++)
|
|
{
|
|
sendBit((byte >> i) & 1);
|
|
}
|
|
}
|
|
|
|
static inline u32 receiveBit(void)
|
|
{
|
|
REG_RCNT1 &= ~(RCNT1_DATA_RTC_SIO | RCNT1_DATA_RTC_SCK);
|
|
rtc_waitByLoop(RTC_WAIT_1US);
|
|
u32 result = REG_RCNT1 & RCNT1_DATA_RTC_SIO;
|
|
REG_RCNT1 |= RCNT1_DATA_RTC_SCK;
|
|
rtc_waitByLoop(RTC_WAIT_1US);
|
|
return result;
|
|
}
|
|
|
|
static inline u32 receiveByte(void)
|
|
{
|
|
// CS and SCK output, SIO input, CS high
|
|
sio_setRtcPins(
|
|
RCNT1_DIR_RTC_CS_OUTPUT | RCNT1_DIR_RTC_SCK_OUTPUT,
|
|
RCNT1_DATA_RTC_CS);
|
|
u32 result = 0;
|
|
for (u32 i = 0; i < 8; i++)
|
|
{
|
|
result = (result >> 1) | (receiveBit() << 7);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static void startTransfer(void)
|
|
{
|
|
// to use the rtc pins we must be in gpio mode
|
|
sio_setGpioMode(RCNT0_L_MODE_GPIO);
|
|
// all rtc pins to output, SCK high
|
|
sio_setRtcPins(
|
|
RCNT1_DIR_RTC_CS_OUTPUT | RCNT1_DIR_RTC_SCK_OUTPUT | RCNT1_DIR_RTC_SIO_OUTPUT,
|
|
RCNT1_DATA_RTC_SCK);
|
|
rtc_waitByLoop(RTC_WAIT_200NS); // setup/hold
|
|
// set CS high
|
|
sio_setRtcChipSelect(true);
|
|
rtc_waitByLoop(RTC_WAIT_200NS); // setup/hold
|
|
}
|
|
|
|
static void endTransfer(void)
|
|
{
|
|
rtc_waitByLoop(RTC_WAIT_200NS); // setup/hold
|
|
// set CS low
|
|
sio_setRtcChipSelect(false);
|
|
rtc_waitByLoop(RTC_WAIT_200NS); // setup/hold
|
|
}
|
|
|
|
static int bcdToDecimal(u8 bcd)
|
|
{
|
|
u32 ones = bcd & 0xF;
|
|
if (ones > 9)
|
|
return -1;
|
|
u32 tens = bcd >> 4;
|
|
if (tens > 9)
|
|
return -1;
|
|
return tens * 10 + ones;
|
|
}
|
|
|
|
static u8 decimalToBcd(u32 decimal)
|
|
{
|
|
u32 ones = decimal % 10;
|
|
u32 tens = decimal / 10;
|
|
return (tens << 4) | ones;
|
|
}
|
|
|
|
static void alarmTo24Hour(rtc_alarm_t* alarm)
|
|
{
|
|
int alarm1Hour = bcdToDecimal(alarm->hour);
|
|
if (alarm1Hour < 0 || alarm1Hour > 23)
|
|
{
|
|
alarm->hour = 0;
|
|
alarm->amPm = RTC_AM;
|
|
}
|
|
else if (alarm->amPm != RTC_AM && alarm1Hour < 12)
|
|
{
|
|
alarm->hour = decimalToBcd(alarm1Hour + 12);
|
|
}
|
|
else if (alarm1Hour >= 12)
|
|
{
|
|
alarm->amPm = RTC_PM;
|
|
}
|
|
}
|
|
|
|
void rtc_init(void)
|
|
{
|
|
u32 status1 = rtc_readStatus1();
|
|
u32 status2 = rtc_readStatus2();
|
|
if ((status1 & (RTC_STATUS1_POC | RTC_STATUS1_BLD)) || (status2 & RTC_STATUS2_TEST))
|
|
{
|
|
status1 |= RTC_STATUS1_RESET;
|
|
rtc_writeStatus1(status1);
|
|
}
|
|
|
|
// disable all rtc irqs
|
|
status2 &= ~(RTC_STATUS2_INT1FE | RTC_STATUS2_INT1ME | RTC_STATUS2_INT1AE | RTC_STATUS2_32KE);
|
|
status2 &= ~RTC_STATUS2_INT2AE;
|
|
rtc_writeStatus2(status2);
|
|
|
|
if (!(status1 & RTC_STATUS1_24HOUR))
|
|
{
|
|
status1 |= RTC_STATUS1_24HOUR;
|
|
rtc_writeStatus1(status1);
|
|
rtc_alarm_t alarm1;
|
|
rtc_readAlarm1(&alarm1);
|
|
alarmTo24Hour(&alarm1);
|
|
rtc_writeAlarm1(&alarm1);
|
|
rtc_alarm_t alarm2;
|
|
rtc_readAlarm2(&alarm2);
|
|
alarmTo24Hour(&alarm2);
|
|
rtc_writeAlarm2(&alarm2);
|
|
}
|
|
}
|
|
|
|
void rtc_readRegister(u32 reg, u8* dst, u32 length)
|
|
{
|
|
reg |= 0x80; // read
|
|
startTransfer();
|
|
sendByte(reg);
|
|
for (u32 i = 0; i < length; i++)
|
|
dst[i] = receiveByte();
|
|
endTransfer();
|
|
}
|
|
|
|
void rtc_writeRegister(u32 reg, const u8* src, u32 length)
|
|
{
|
|
reg &= ~0x80; // write
|
|
startTransfer();
|
|
sendByte(reg);
|
|
for (u32 i = 0; i < length; i++)
|
|
sendByte(src[i]);
|
|
endTransfer();
|
|
}
|