- Wed Apr 26, 2017 3:08 pm
#194551
Hi! I'm trying to name datafiles with the DeadOn RTC time and populate that file with data streamed over UART0. I was able to echo time (YY_MO_DD_hh_mm_ss) from the RTC every 1 second to my computer COM port using UART1 and name files using this received time, but this was only accomplished by inserting delay_ms(...) statements throughout the code. Without these delays, the RTC time would be "00FF00FFFFFF" instead of the actual time ("170422172310" for example). What's even more strange is that adding variables or deleting unused code elsewhere in the program would also result in the "00FF00FFFFFF" output...even if the added/deleted code had nothing to do with SPI1 or the RTC. I tried playing with interrupt declarations, SPI1 functions implementations, RTC function implementations, etc. but nothing worked. Searching online for clarity yielded nothing as well, and the LPC2148 and DS3234 manuals didn't provide me with a good idea at where the problem is coming from in my implementation. I want to get this working, but I really want to understand WHY my firmware is behaving in this way.
the SPI1 code and main.c code are below:
the SPI1 code and main.c code are below:
Code: Select all
/*****************************************************************************
* ssp.h: Header file for Philips LPC214x Family Microprocessors
*
* Copyright(C) 2006, Philips Semiconductor
* All rights reserved.
*
* History
* 2005.10.01 ver 1.00 Prelimnary version, first Release
*
******************************************************************************/
#ifndef __SSP_H__
#define __SSP_H__
#include <stdint.h>
#define SSP_SS_PIN 20
/* SPI read and write buffer size */
#define BUFSIZE 256
#define FIFOSIZE 8
/* don't use CS, set CS as GPIO that you have total control
of the sequence */
#define USE_CS 0
/* SPI select pin */
#define SPI1_SEL 0x00100000
/* Chip Select Defines for SSP */
#define SSP_SS_IOCLR IOCLR0
#define SSP_SS_IOSET IOSET0
#define select_ssp() SSP_SS_IOCLR |= (1<<SSP_SS_PIN)
#define unselect_ssp() SSP_SS_IOSET |= (1<<SSP_SS_PIN)
/* SPI Status register */
#define SSPSR_TFE 1 << 0
#define SSPSR_TNF 1 << 1
#define SSPSR_RNE 1 << 2
#define SSPSR_RFF 1 << 3
#define SSPSR_BSY 1 << 4
/* SPI 1 CR0 register */
#define SSPCR0_DSS 1 << 0
#define SSPCR0_FRF 1 << 4
#define SSPCR0_CPOL 1 << 6
#define SSPCR0_CPHA 1 << 7
#define SSPCR0_SCR 1 << 8
/* SPI 1 CR1 register */
#define SSPCR1_LBM 1 << 0
#define SSPCR1_NM 0 << 0
#define SSPCR1_SSE 1 << 1
#define SSPCR1_MS 1 << 2
#define SSPCR1_SOD 1 << 3
/* SPI 1 Interrupt Mask Set/Clear register */
#define SSPIMSC_RORIM 1 << 0
#define SSPIMSC_RTIM 1 << 1
#define SSPIMSC_RXIM 1 << 2
#define SSPIMSC_TXIM 1 << 3
/* SPI 1 Interrupt Status register */
#define SSPRIS_RORRIS 1 << 0
#define SSPRIS_RTRIS 1 << 1
#define SSPRIS_RXRIS 1 << 2
#define SSPRIS_TXRIS 1 << 3
/* SPI 1 Masked Interrupt register */
#define SSPMIS_RORMIS 1 << 0
#define SSPMIS_RTMIS 1 << 1
#define SSPMIS_RXMIS 1 << 2
#define SSPMIS_TXMIS 1 << 3
/* SPI 1 Interrupt clear register */
#define SSPICR_RORIC 1 << 0
#define SSPICR_RTIC 1 << 1
extern void SPI1Init( void );
extern void SPI1Send( uint8_t wbyte );
extern uint8_t SPI1Receive( void );
#endif /* __SSP_H__ */
/*****************************************************************************
** End Of File
******************************************************************************/
Code: Select all
/*****************************************************************************
* ssp.c: SSP C file for Philips LPC214x Family Microprocessors
*
* Copyright(C) 2006, Philips Semiconductor
* All rights reserved.
*
* History
* 2005.10.01 ver 1.00 Prelimnary version, first Release
*
*****************************************************************************/
#include "LPC214x.h" /* LPC21XX Peripheral Registers */
#include "type.h"
#include "irq.h"
#include "ssp.h"
extern BYTE SPIWRData[BUFSIZE];
extern BYTE SPIRDData[BUFSIZE];
extern unsigned int CurrentTxIndex;
extern unsigned int CurrentRxIndex;
/*****************************************************************************
** Function name: SPI1Init
**
** Descriptions: SPI1(SSP) port initialization routine
**
** parameters: None
** Returned value: true or false, if the interrupt handler
** can't be installed correctly, return false.
**
*****************************************************************************/
void SPI1Init( void )
{
BYTE i, Dummy;
/* Configure PIN connect block */
/* bit 32, 54, 76 are 0x10, bit 98 are 0x00 */
/* port 0 bits 17, 18, 19, 20 are SSP port SCK1, MISO1, MOSI1, and SSEL1 */
/* set SSEL to GPIO pin that you will have the totoal freedom to set/reset
the SPI chip-select pin */
SSPCR1 = SSPCR1_NM; /* SSP master in normal operation mode */
IODIR0 = SPI1_SEL; /* SSEL is output */
unselect_ssp(); /* set SSEL to high */
//VPBDIV = 0x02; /* Set PCLK to the same as CCLK */
/* Set DSS data to 8-bit, Frame format SPI, CPOL = 0, CPHA = 1, and SCR is 15 */
SSPCR0 = 0x0787;
SSPCPSR = 0x02; /* SSPCPSR clock prescale register, master mode, minimum divisor is 0x02 */
for ( i = 0; i < FIFOSIZE; i++ )
{
Dummy = SSPDR; /* clear the RxFIFO */
}
/* Device select as master, SSP Enabled, normal operational mode */
SSPCR1 = SSPCR1_NM | SSPCR1_SSE;
}
/*****************************************************************************
** Function name: SPI1Send
**
** Descriptions: Send a block of data to the SPI1(SSP) port
**
** parameters: unsigned int
** Returned value: None
**
*****************************************************************************/
void SPI1Send( uint8_t wbyte )
{
SSPDR = wbyte;
while ( !(SSPSR & SSPSR_BSY) ); // Wait for byte to be shifted out
}
/*****************************************************************************
** Function name: SPI1Receive
** Descriptions: the module will receive a block of data from
** the SPI1(SSP) port.
**
** parameters: none
** Returned value: unsigned int
**
*****************************************************************************/
uint8_t SPI1Receive( void )
{
while ( !(SSPSR & SSPSR_BSY) );
return SSPDR;
}
/******************************************************************************
** End Of File
******************************************************************************/
Code: Select all
/*********************************************************************************
* Logomatic V2 Firmware
* Sparkfun Electronics 2008
* Modified by JayDel325
* ******************************************************************************/
/*******************************************************
* Header Files
******************************************************/
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include "LPC214x.h"
#include "ssp.h"
#include <string.h>
//UART0 Debugging
#include "serial.h"
#include "rprintf.h"
//Needed for main function calls
#include "main_msc.h"
#include "fat.h"
#include "armVIC.h"
#include "itoa.h"
#include "rootdir.h"
#include "sd_raw.h"
#include "string_printf.h"
#include "delay.h"
/*******************************************************
* Global Variables
******************************************************/
#define ON 1
#define OFF 0
#define THRE (1<<5) // Transmit Holding Register Empty
#define RDR (1<<0) // Receiver Data Ready
#define BUF_SIZE 512
char RX_array1[BUF_SIZE];
char RX_array2[BUF_SIZE];
char log_array1 = 0;
char log_array2 = 0;
short RX_in = 0;
char get_frame = 0;
int u = 0;
signed int stringSize;
struct fat_file_struct* handle;
struct fat_file_struct * fd;
char stringBuf[256];
//int time[7] = {2,17,2017,0,11,34,40};
uint8_t rtc_time[30];
uint8_t day;
uint8_t month;
uint8_t year;
uint8_t hour;
uint8_t minute;
uint8_t second;
// Default Settings
static char mode = 0;
static char asc = 'N';
static int baud = 9600;
static int freq = 100;
static char trig = '$';
static short frame = 100;
static char ad1_7 = 'N';
static char ad1_6 = 'N';
static char ad1_3 = 'N';
static char ad1_2 = 'N';
static char ad0_4 = 'N';
static char ad0_3 = 'N';
static char ad0_2 = 'N';
static char ad0_1 = 'N';
static char rtc_set = 'N';
/*******************************************************
* Function Declarations
******************************************************/
void Initialize(void);
void setup_uart0(int newbaud, char want_ints);
void setup_uart1(int newbaud, char want_ints);
void mode_0(void);
void mode_1(void);
void mode_2(void);
void mode_3(void);
void mode_4(void);
void mode_action(void);
void Log_init(void);
void test(void);
void stat(int statnum, int onoff);
void AD_conversion(int regbank);
void feed(void);
//UART1 Functions
char U1Read(void);
void U1Write(char data);
//Real-time Clock Functions for DS3234
void setTime(uint8_t mo, uint8_t d, uint8_t y, uint8_t h, uint8_t mi, uint8_t s);
void readTime(void);
void RTC_Init(void);
//BHW Never defined... static void IRQ_Routine(void) __attribute__ ((interrupt("IRQ")));
static void UART0ISR(void); //__attribute__ ((interrupt("IRQ")));
static void UART1ISR(void);
static void UART0ISR_2(void); //__attribute__ ((interrupt("IRQ")));
static void MODE2ISR(void); //__attribute__ ((interrupt("IRQ")));
void FIQ_Routine(void); //__attribute__ ((interrupt("FIQ")));
void SWI_Routine(void); //__attribute__ ((interrupt("SWI")));
void UNDEF_Routine(void); //__attribute__ ((interrupt("UNDEF")));
void fat_initialize(void);
int modulo(int num, int div);
uint8_t uint2bcd(uint8_t ival);
/*******************************************************
* MAIN
******************************************************/
int main (void)
{
int i;
char name[32];
int count = 0;
enableFIQ();
Initialize();
setup_uart0(9600, 0);
fat_initialize();
// Flash Status Lights
for(i = 0; i < 5; i++)
{
stat(0,ON);
delay_ms(50);
stat(0,OFF);
stat(1,ON);
delay_ms(50);
stat(1,OFF);
}
Log_init();
count++; //BHW TODO: this makes the count start from 1, not 0 to match docs
string_printf(name,"LOG%02d.txt",count);
while(root_file_exists(name))
{
count++;
if(count == 250) //BHW TODO: This less than 250 limit doesn't match docs
{
rprintf("Too Many Logs!\n\r");
while(1)
{
stat(0,ON);
stat(1,ON);
delay_ms(1000);
stat(0,OFF);
stat(1,OFF);
delay_ms(1000);
}
}
string_printf(name,"LOG%02d.txt",count);
}
delay_ms(10); //inserted only because it helped get proper output from DS3234
if (rtc_set == 'Y')
{
//RTC_Init(); //only need to initialize DS3234 once
day = uint2bcd(day);
month = uint2bcd(month);
year = uint2bcd(year);
second = uint2bcd(second);
minute = uint2bcd(minute);
hour = uint2bcd(hour);
setTime(day,month,year,hour,minute,second);
}
if(mode == 0){ mode_0(); }
else if(mode == 1){ mode_1(); }
else if(mode == 2){ mode_2(); }
else if(mode == 3){ mode_3(); }
else if(mode == 4){ mode_4(); }
return 0;
}
/*******************************************************
* Initialize
******************************************************/
#define PLOCK 0x400
void Initialize(void)
{
rprintf_devopen(putc_serial0);
rprintf_devopen(putc_serial1); //JD
// 0xCF351505 = 0b 11 00 11 11 00 11 01 01 00 01 01 01 00 00 01 01
// 0x154418A9 = 0b 00 01 01 01 01 00 01 00 00 01 10 00 10 10 10 01
//
// Symbol | Value | Function
// -------|-------|----------------------------------
// PINSEL0| |
// P0.0 | 01 | TXD (UART0)
// P0.1 | 01 | RxD (UART0)
// P0.2 | 00 | GPIO Port 0.2
// P0.3 | 00 | GPIO Port 0.3
// P0.4 | 01 | SCK0 (SPI0)
// P0.5 | 01 | MISO0 (SPI0)
// P0.6 | 01 | MOSI0 (SPI0)
// P0.7 | 00 | GPIO Port 0.7
// P0.8 | 01 | TXD (UART1)
// P0.9 | 01 | RXD (UART1)
// P0.10 | 11 | AD1.2
// P0.11 | 00 | GPIO Port 0.11
// P0.12 | 11 | AD1.3
// P0.13 | 11 | AD1.4
// P0.14 | 00 | GPIO Port 0.14
// P0.15 | 11 | AD1.5
// PINSEL1| |
// P0.16 | 01 | EINT0
// P0.17 | 10 | SCK1 (SSP)
// P0.18 | 10 | MISO1 (SSP)
// P0.19 | 10 | MOSI1 (SSP)
// P0.20 | 00 | GPIO Port 0.20
// P0.21 | 10 | AD1.6
// P0.22 | 01 | AD1.7
// P0.23 | 00 | GPIO Port 0.23
// P0.24 | 00 | Reserved
// P0.25 | 01 | AD0.4
// P0.26 | 00 | Reserved
// P0.27 | 01 | Reserved
// P0.28 | 01 | AD0.1
// P0.29 | 01 | AD0.2
// P0.30 | 01 | AD0.3
// P0.31 | 00 | GPO Port only
PINSEL0 = 0xCF351505;
PINSEL1 = 0x154418A9;
// P0.0 = INPUT | TXD (UART0)
// P0.1 = INPUT | RxD (UART0)
// P0.2 = OUTPUT | STAT0 LED
// P0.3 = INPUT | STOP Button
// P0.4 = INPUT | SCK0 (SPI0)
// P0.5 = INPUT | MISO0 (SPI0)
// P0.6 = INPUT | MOSI0 (SPI0)
// P0.7 = OUTPUT | Chip Select 0
// P0.8 = INPUT | TXD (UART1)
// P0.9 = INPUT | RXD (UART1)
// P0.10 = INPUT | AD1.2
// P0.11 = OUTPUT | STAT1 LED
// P0.12 = INPUT | AD1.3
// P0.13 = INPUT | AD1.4
// P0.14 = INPUT | GPIO Port 0.14
// P0.15 = INPUT | AD1.5
// P0.16 = INPUT | EINT0
// P0.17 = INPUT | SCK1 (SSP)
// P0.18 = INPUT | MISO1 (SSP)
// P0.19 = INPUT | MOSI1 (SSP)
// P0.20 = OUTPUT | GPIO Port 0.20
// P0.21 = INPUT | AD1.6
// P0.22 = INPUT | AD1.7
// P0.23 = INPUT | GPIO Port 0.23
// P0.24 = INPUT | Reserved
// P0.25 = INPUT | AD0.4
// P0.26 = INPUT | Reserved
// P0.27 = INPUT | Reserved
// P0.28 = INPUT | AD0.1
// P0.29 = INPUT | AD0.2
// P0.30 = INPUT | AD0.3
// P0.31 = INPUT | GPO Port only
// Rest of Port 0 are inputs
IODIR0 |= 0x00000884;
IOSET0 = 0x00000080; // Set P0.7 HIGH | CS0 HIGH
S0SPCCR = 0x08; // SPI clk to be pclk/8
S0SPCR = 0x30; // master, msb, first clk edge, active high, no ints
SPI1Init(); // ssp.c
}
// Make values in PLL control & configure registers take effect
void feed(void)
{
// Interrupts must be disabled to make consecutive APB bus cycles
PLLFEED=0xAA;
PLLFEED=0x55;
}
/*******************************************************************************
* Function: UART0ISR();
*
* Description: UART0ISR is the routine that runs every time the UART0
* interrupt triggers. This trigger happens whenever the
* uart0 read buffer is not empty. This function is designed
* to collect data from a serial device attached to UART0 of
* the Logomatic.
*
* Inputs: None
*
* Outputs: None
**********************************************************************************/
static void UART0ISR(void)
{
if(RX_in < BUF_SIZE)
{
RX_array1[RX_in] = U0RBR;
RX_in++;
if(RX_in == BUF_SIZE) log_array1 = 1;
}
else if(RX_in >= BUF_SIZE)
{
RX_array2[RX_in-BUF_SIZE] = U0RBR;
RX_in++;
if(RX_in == 2 * BUF_SIZE)
{
log_array2 = 1;
RX_in = 0;
}
}
U0IIR; // Have to read this to clear the interrupt
VICVectAddr = 0; // Acknowledge interrupt
}
/*******************************************************************************
* Function: UART1ISR();
*
* Description: UART1ISR is the routine that runs every time the UART1
* interrupt triggers. This trigger happens whenever the
* uart1 transmit buffer is empty. This function echos the
* RTC time to the UART1 so engineers can verify RTC was
* properly set.
*
* Inputs: None
*
* Outputs: None
**********************************************************************************/
/*Unused interrupt routine*/
static void UART1ISR(void)
{
int TimeDate [7]={0,0,0,0,0,0,0};
delay_ms(500);
char test_spi[15];
select_ssp();
SPI1Send(0x00);
SPI1Receive();
SPI1Send(0x00);
unsigned char n = SPI1Receive();
unselect_ssp();
unsigned char a = (n & 0x0F);
unsigned char b = (n & 0x70)>>4;
TimeDate[0]=a+b*10;
string_printf(test_spi,"%x",n);
int c = 0;
while (test_spi[c] != '\0')
{
U1Write(test_spi[c]);
U1Write(0x80);
c++;
}
U1Write('\n');
c=0;
U1IIR; // Have to read this to clear the interrupt
VICVectAddr = 0; // Acknowledge interrupt
}
/*******************************************************************************
* Function: UART0ISR_2();
*
* Description: UART0ISR_2 is the routine that runs every time the UART0
* interrupt triggers. This interrupt happens whenever the
* uart0 read buffer is not empty. This function is designed
* to collect data from a serial device attached to UART0 of
* the Logomatic, once an ASCII trigger is sent over UART0.
*
* Inputs: None
*
* Outputs: None
**********************************************************************************/
static void UART0ISR_2(void)
{
char temp;
temp = U0RBR; // Read a byte from UART0 receive buffer
if(temp == trig)
{
get_frame = 1;
}
if(get_frame)
{
if(RX_in < frame)
{
RX_array1[RX_in] = temp;
RX_in++;
if(RX_in == frame)
{
// Delimiters
RX_array1[RX_in] = '\n';
RX_array1[RX_in + 1] = '\r';
log_array1 = 1;
get_frame = 0;
}
}
else if(RX_in >= frame)
{
RX_array2[RX_in - frame] = temp;
RX_in++;
if(RX_in == 2*frame)
{
// Delimiters
RX_array2[RX_in - frame] = '\n';
RX_array2[RX_in + 1 - frame] = '\r';
log_array2 = 1;
get_frame = 0;
RX_in = 0;
}
}
}
temp = U0IIR; // Have to read this to clear the interrupt
VICVectAddr = 0; // Acknowledge interrupt
}
//pushValue is needed for the "sample" function, exact operation not understood
static inline int pushValue(char* q, int ind, int value)
{
char* p = q + ind;
if(asc == 'Y') // ASCII
{
// itoa returns the number of bytes written excluding
// trailing '\0', hence the "+ 1"
return itoa(value, p, 10) + ind + 1;
}
else if(asc == 'N') // binary
{
p[0] = value >> 8;
p[1] = value;
return ind + 2;
}
else // invalid
{
return ind;
}
}
//sample is used in the MODE2ISR routine. used to perform ADC operations
static int sample(char* q, int ind, volatile unsigned long* ADxCR,
volatile unsigned long* ADxGDR, int mask, char adx_bit)
{
if(adx_bit == 'Y')
{
int value = 0;
*ADxCR = 0x00020FF00 | mask;
*ADxCR |= 0x01000000; // start conversion
while((value & 0x80000000) == 0)
{
value = *ADxGDR;
}
*ADxCR = 0x00000000;
// The upper ten of the lower sixteen bits of 'value' are the
// result. The result itself is unsigned. Hence a cast to
// 'unsigned short' yields the result with six bits of
// noise. Those are removed by the following shift operation.
return pushValue(q, ind, (unsigned short)value >> 6);
}
else
{
return ind;
}
}
/*******************************************************************************
* Function: MODE2ISR();
*
* Description: MODE2ISR is the routine that runs every time the timer
* interrupt for the ADC triggers. This function is designed
* to collect data from analog channels at the user specified
* data rate.
*
* Inputs: None
*
* Outputs: None
**********************************************************************************/
static void MODE2ISR(void)
{
int ind = 0;
int j;
char q[50];
T0IR = 1; // reset TMR0 interrupt
for(j = 0; j < 50; j++)
{
q[j] = 0;
}
#define SAMPLE(X, BIT) ind = sample(q, ind, &AD##X##CR, &AD##X##GDR, 1 << BIT, ad##X##_##BIT)
SAMPLE(1, 3);
SAMPLE(0, 3);
SAMPLE(0, 2);
SAMPLE(0, 1);
SAMPLE(1, 2);
SAMPLE(0, 4);
SAMPLE(1, 7);
SAMPLE(1, 6);
#undef SAMPLE
for(j = 0; j < ind; j++)
{
if(RX_in < BUF_SIZE)
{
RX_array1[RX_in] = q[j];
RX_in++;
if(RX_in == BUF_SIZE) log_array1 = 1;
}
else if(RX_in >= BUF_SIZE)
{
RX_array2[RX_in - BUF_SIZE] = q[j];
RX_in++;
if(RX_in == 2 * BUF_SIZE)
{
log_array2 = 1;
RX_in = 0;
}
}
}
if(RX_in < BUF_SIZE)
{
if(asc == 'N') { RX_array1[RX_in] = '$'; }
else if(asc == 'Y'){ RX_array1[RX_in] = 13; }
RX_in++;
if(RX_in == BUF_SIZE) log_array1 = 1;
}
else if(RX_in >= BUF_SIZE)
{
if(asc == 'N') RX_array2[RX_in - BUF_SIZE] = '$';
else if(asc == 'Y'){ RX_array2[RX_in - BUF_SIZE] = 13; }
RX_in++;
if(RX_in == 2 * BUF_SIZE)
{
log_array2 = 1;
RX_in = 0;
}
}
if(RX_in < BUF_SIZE)
{
if(asc == 'N') RX_array1[RX_in] = '$';
else if(asc == 'Y'){ RX_array1[RX_in] = 10; }
RX_in++;
if(RX_in == BUF_SIZE) log_array1 = 1;
}
else if(RX_in >= BUF_SIZE)
{
if(asc == 'N') RX_array2[RX_in - BUF_SIZE] = '$';
else if(asc == 'Y'){ RX_array2[RX_in - BUF_SIZE] = 10; }
RX_in++;
if(RX_in == 2 * BUF_SIZE)
{
log_array2 = 1;
RX_in = 0;
}
}
VICVectAddr = 0; // Acknowledge interrupt
}
//This function is for fast interrupt requests, but is not used in this program
void FIQ_Routine(void)
{
int j;
stat(0,ON);
for(j = 0; j < 5000000; j++); // TODO: Why are we using a blocking delay n ISR
stat(0,OFF);
U0RBR; // Trash oldest byte in UART0 Rx FiFO Why??
U0IIR; // Have to read this to clear the interrupt
// TODO: Should we be acking int here?
}
//This is a software interrupt routine. Not used.
void SWI_Routine(void)
{
while(1);
}
//Undefined routine. Not used.
void UNDEF_Routine(void)
{
stat(0,ON);
}
/*******************************************************************************
* Function: setup_uart0(int newbaud, char want_ints)
*
* Description: setup_uart0 is the routine that is called to define the uart0
* port. Baud rate is established, and interrupts are addressed
* and enabled.
*
* Inputs: int newbaud: the user defined baud rate
* char want_ints: desired interrupt priority
*
* Outputs: None
**********************************************************************************/
void setup_uart0(int newbaud, char want_ints)
{
baud = newbaud;
U0LCR = 0x83; // 8 bits, no parity, 1 stop bit, DLAB = 1
if(baud == 1200)
{
U0DLM = 0x0C;
U0DLL = 0x00;
}
else if(baud == 2400)
{
U0DLM = 0x06;
U0DLL = 0x00;
}
else if(baud == 4800)
{
U0DLM = 0x03;
U0DLL = 0x00;
}
else if(baud == 9600)
{
U0DLM = 0x01;
U0DLL = 0x80;
}
else if(baud == 19200)
{
U0DLM = 0x00;
U0DLL = 0xC0;
}
else if(baud == 38400)
{
U0DLM = 0x00;
U0DLL = 0x60;
}
else if(baud == 57600)
{
U0DLM = 0x00;
U0DLL = 0x40;
}
else if(baud == 115200)
{
U0DLM = 0x00;
U0DLL = 0x20;
}
U0FCR = 0x01;
U0LCR = 0x03;
if(want_ints == 1)
{
enableIRQ();
VICIntSelect &= ~0x00000040;
VICIntEnable |= 0x00000040;
VICVectCntl1 = 0x26;
VICVectAddr1 = (unsigned int)UART0ISR;
U0IER = 0x01;
}
else if(want_ints == 2)
{
enableIRQ();
VICIntSelect &= ~0x00000040;
VICIntEnable |= 0x00000040;
VICVectCntl2 = 0x26;
VICVectAddr2 = (unsigned int)UART0ISR_2;
U0IER = 0X01;
}
else if(want_ints == 0)
{
VICIntEnClr = 0x00000040;
U0IER = 0x00;
}
}
/*******************************************************************************
* Function: setup_uart1(int newbaud, char want_ints)
*
* Description: setup_uart1 is the routine that is called to define the uart1
* port. Baud rate is established, and interrupts are addressed
* and enabled.
*
* Inputs: int newbaud: the user defined baud rate
* char want_ints: desired interrupt priority
*
* Outputs: None
**********************************************************************************/
void setup_uart1(int newbaud, char want_ints)
{
baud = newbaud;
U1LCR = 0x83; // 8 bits, no parity, 1 stop bit, DLAB = 1
if(baud == 1200)
{
U1DLM = 0x0C;
U1DLL = 0x00;
}
else if(baud == 2400)
{
U1DLM = 0x06;
U1DLL = 0x00;
}
else if(baud == 4800)
{
U1DLM = 0x03;
U1DLL = 0x00;
}
else if(baud == 9600)
{
U1DLM = 0x01;
U1DLL = 0x80;
}
else if(baud == 19200)
{
U1DLM = 0x00;
U1DLL = 0xC0;
}
else if(baud == 38400)
{
U1DLM = 0x00;
U1DLL = 0x60;
}
else if(baud == 57600)
{
U1DLM = 0x00;
U1DLL = 0x40;
}
else if(baud == 115200)
{
U1DLM = 0x00;
U1DLL = 0x20;
}
U1FCR = 0x01;
U1LCR = 0x03;
if(want_ints == 3)
{
enableIRQ();
VICIntSelect &= ~0x00000080;
VICIntEnable |= 0x00000080;
VICVectCntl3 = 0x27;
VICVectAddr3 = (unsigned int)UART1ISR;
U1IER = 0X02;
}
else if(want_ints == 0)
{
VICIntEnClr = 0x00000080;
U1IER = 0x00;
}
}
/*******************************************************************************
* Function: stat(int statnum, int onoff)
*
* Description: stat is the routine that drives the status lights on the
* Logomatic.
*
* Inputs: int statnum: desired status light (0 or 1)
* int onoff: status light state (ON or OFF)
*
* Outputs: None
**********************************************************************************/
void stat(int statnum, int onoff)
{
if(statnum) // Stat 1
{
if(onoff){ IOCLR0 = 0x00000800; } // On
else { IOSET0 = 0x00000800; } // Off
}
else // Stat 0
{
if(onoff){ IOCLR0 = 0x00000004; } // On
else { IOSET0 = 0x00000004; } // Off
}
}
/*******************************************************************************
* Function: Log_init()
*
* Description: Log_init either creates a _LOGCON.ini file or reads the
* _LOGCON.ini already on the microSD card inserted in the
* Logomatic. Configuration parameters are extracted from the
* _LOGCON.ini file.
*
* Inputs: None
*
* Outputs: None
**********************************************************************************/
void Log_init(void)
{
int x, mark = 0, ind = 0;
char temp, temp2 = 0, safety = 0;
// signed char handle;
if(root_file_exists("_LOGCON.ini"))
{
//rprintf("\n\rFound _LOGCON.ini\n");
fd = root_open("_LOGCON.ini");
stringSize = fat_read_file(fd, (unsigned char *)stringBuf, 512);
stringBuf[stringSize] = '\0';
fat_close_file(fd);
}
else
{
//rprintf("Couldn't find _LOGCON.ini, creating...\n");
fd = root_open_new("_LOGCON.ini");
if(fd == NULL)
{
rprintf("Error creating _LOGCON.ini, locking up...\n\r");
while(1)
{
stat(0,ON);
delay_ms(50);
stat(0,OFF);
stat(1,ON);
delay_ms(50);
stat(1,OFF);
}
}
strcpy(stringBuf, "MODE = 0\r\nASCII = N\r\nBaud = 4\r\nFrequency = 100\r\nTrigger Character = $\r\nText Frame = 100\r\nAD1.3 = N\r\nAD0.3 = N\r\nAD0.2 = N\r\nAD0.1 = N\r\nAD1.2 = N\r\nAD0.4 = N\r\nAD1.7 = N\r\nAD1.6 = N\r\nSet RTC = N\r\nDate_Time = 000101_000000\r\nSafety On = Y\r\n");
stringSize = strlen(stringBuf);
fat_write_file(fd, (unsigned char*)stringBuf, stringSize);
sd_raw_sync();
}
for(x = 0; x < stringSize; x++)
{
temp = stringBuf[x];
if(temp == 10)
{
mark = x;
ind++;
if(ind == 1)
{
mode = stringBuf[mark-2]-48; // 0 = auto uart, 1 = trigger uart, 2 = adc
rprintf("mode = %d\n\r",mode);
}
else if(ind == 2)
{
asc = stringBuf[mark-2]; // default is 'N'
rprintf("asc = %c\n\r",asc);
}
else if(ind == 3)
{
if(stringBuf[mark-2] == '1'){ baud = 1200; }
else if(stringBuf[mark-2] == '2'){ baud = 2400; }
else if(stringBuf[mark-2] == '3'){ baud = 4800; }
else if(stringBuf[mark-2] == '4'){ baud = 9600; }
else if(stringBuf[mark-2] == '5'){ baud = 19200; }
else if(stringBuf[mark-2] == '6'){ baud = 38400; }
else if(stringBuf[mark-2] == '7'){ baud = 57600; }
else if(stringBuf[mark-2] == '8'){ baud = 115200; }
rprintf("baud = %d\n\r",baud);
}
else if(ind == 4)
{
freq = (stringBuf[mark-2]-48) + (stringBuf[mark-3]-48) * 10;
if((stringBuf[mark-4] >= 48) && (stringBuf[mark-4] < 58))
{
freq+= (stringBuf[mark-4]-48) * 100;
if((stringBuf[mark-5] >= 48) && (stringBuf[mark-5] < 58)){ freq += (stringBuf[mark-5]-48)*1000; }
}
rprintf("freq = %d\n\r",freq);
}
else if(ind == 5)
{
trig = stringBuf[mark-2]; // default is $
rprintf("trig = %c\n\r",trig);
}
else if(ind == 6)
{
frame = (stringBuf[mark-2]-48) + (stringBuf[mark-3]-48) * 10 + (stringBuf[mark-4]-48)*100;
if(frame > 510){ frame = 510; } // up to 510 characters
rprintf("frame = %d\n\r",frame);
}
else if(ind == 7)
{
ad1_3 = stringBuf[mark-2]; // default is 'N'
if(ad1_3 == 'Y'){ temp2++; }
rprintf("ad1_3 = %c\n\r",ad1_3);
}
else if(ind == 8)
{
ad0_3 = stringBuf[mark-2]; // default is 'N'
if(ad0_3 == 'Y'){ temp2++; }
rprintf("ad0_3 = %c\n\r",ad0_3);
}
else if(ind == 9)
{
ad0_2 = stringBuf[mark-2]; // default is 'N'
if(ad0_2 == 'Y'){ temp2++; }
rprintf("ad0_2 = %c\n\r",ad0_2);
}
else if(ind == 10)
{
ad0_1 = stringBuf[mark-2]; // default is 'N'
if(ad0_1 == 'Y'){ temp2++; }
rprintf("ad0_1 = %c\n\r",ad0_1);
}
else if(ind == 11)
{
ad1_2 = stringBuf[mark-2]; // default is 'N'
if(ad1_2 == 'Y'){ temp2++; }
rprintf("ad1_2 = %c\n\r",ad1_2);
}
else if(ind == 12)
{
ad0_4 = stringBuf[mark-2]; // default is 'N'
if(ad0_4 == 'Y'){ temp2++; }
rprintf("ad0_4 = %c\n\r",ad0_4);
}
else if(ind == 13)
{
ad1_7 = stringBuf[mark-2]; // default is 'N'
if(ad1_7 == 'Y'){ temp2++; }
rprintf("ad1_7 = %c\n\r",ad1_7);
}
else if(ind == 14)
{
ad1_6 = stringBuf[mark-2]; // default is 'N'
if(ad1_6 == 'Y'){ temp2++; }
rprintf("ad1_6 = %c\n\r",ad1_6);
}
else if(ind == 17)
{
safety = stringBuf[mark-2]; // default is 'Y'
rprintf("safety = %c\n\r",safety);
}
else if(ind == 15)
{
rtc_set = stringBuf[mark-2]; // default if 'N'
rprintf("rtc display = %c\n\r",rtc_set);
}
else if(ind == 16)
{
second = (stringBuf[mark-2]-48) + (stringBuf[mark-3]-48)*10;
minute = (stringBuf[mark-4]-48) + (stringBuf[mark-5]-48)*10;
hour = (stringBuf[mark-6]-48) + (stringBuf[mark-7]-48)*10;
day = (stringBuf[mark-9]-48) + (stringBuf[mark-10]-48)*10;
month = (stringBuf[mark-11]-48) + (stringBuf[mark-12]-48)*10;
year = (stringBuf[mark-13]-48) + (stringBuf[mark-14]-48)*10;
}
}
}
if(safety == 'Y')
{
if((temp2 ==10) && (freq > 150)){ freq = 150; }
else if((temp2 == 9) && (freq > 166)){ freq = 166; }
else if((temp2 == 8) && (freq > 187)){ freq = 187; }
else if((temp2 == 7) && (freq > 214)){ freq = 214; }
else if((temp2 == 6) && (freq > 250)){ freq = 250; }
else if((temp2 == 5) && (freq > 300)){ freq = 300; }
else if((temp2 == 4) && (freq > 375)){ freq = 375; }
else if((temp2 == 3) && (freq > 500)){ freq = 500; }
else if((temp2 == 2) && (freq > 750)){ freq = 750; }
else if((temp2 == 1) && (freq > 1500)){ freq = 1500; }
else if((temp2 == 0)){ freq = 100; }
}
if(safety == 'T'){ test(); }
}
/*******************************************************************************
* Function: mode_0()
*
* Description: mode_0 is the routine that runs if Auto UART (mode 0)
* operation is desired by the user. The UART0 port is setup
* and the primary data logging routine is entered.
*
* Inputs: None
*
* Outputs: None
**********************************************************************************/
void mode_0(void) // Auto UART mode
{
rprintf("MODE 0\n\r");
setup_uart0(baud,1);
stringSize = BUF_SIZE;
mode_action();
}
/*******************************************************************************
* Function: mode_1()
*
* Description: mode_1 is the routine that runs if Triggered UART0 (mode 1)
* operation is desired by the user. The UART0 port is setup
* and the primary data logging routine is entered.
*
* Inputs: None
*
* Outputs: None
**********************************************************************************/
void mode_1(void) // Triggered UART Logging
{
rprintf("MODE 1\n\r");
setup_uart0(baud,2);
stringSize = frame + 2;
mode_action();
}
/*******************************************************************************
* Function: mode_2()
*
* Description: mode_2 is the routine that runs if ADC Logging (mode 2)
* operation is desired by the user. Interrupts are enabled and
* rate of interrupts are set. The primary data logging routine
* is entered once interrupt setup is complete.
*
* Inputs: None
*
* Outputs: None
**********************************************************************************/
void mode_2(void) // ADC Logging
{
rprintf("MODE 2\n\r");
enableIRQ();
// Timer0 interrupt is an IRQ interrupt
VICIntSelect &= ~0x00000010;
// Enable Timer0 interrupt
VICIntEnable |= 0x00000010;
// Use slot 2 for UART0 interrupt
VICVectCntl2 = 0x24;
// Set the address of ISR for slot 1
VICVectAddr2 = (unsigned int)MODE2ISR;
T0TCR = 0x00000002; // Reset counter and prescaler
T0MCR = 0x00000003; // On match reset the counter and generate interrupt
T0MR0 = 58982400 / freq;
T0PR = 0x00000000;
T0TCR = 0x00000001; // enable timer
stringSize = BUF_SIZE;
mode_action();
}
/*******************************************************************************
* Function: mode_3()
*
* Description: mode_3 is the routine that runs if Auto UART with RTC (mode 3)
* operation is desired by the user. The UART0 port is setup
* and the primary data logging routine is entered. This mode
* should only be run if the user is certain the RTC has been
* intialized and is set to the desired time.
*
* Inputs: None
*
* Outputs: None
**********************************************************************************/
void mode_3(void) // UART w/ RTC
{
rprintf("MODE 3\n\r");
setup_uart0(baud,1);
stringSize = BUF_SIZE;
mode_action();
}
/*******************************************************************************
* Function: mode_4()
*
* Description: mode_4 is the routine that runs if RTC setup (mode 4)
* operation is desired by the user. The UART1 port is setup,
* the RTC is initialized, the desired time is entered, and
* the primary data logging routine is entered.
*
* Inputs: None
*
* Outputs: None
**********************************************************************************/
void mode_4(void) // Set RTC Time
{
rprintf("MODE 4\n\r");
setup_uart1(baud,0);
stringSize = BUF_SIZE;
mode_action();
}
/*******************************************************************************
* Function: mode_action()
*
* Description: mode_action is the primary data collect routine. It writes
* data to the SD card and flashes lights as the data buffers
* fill up. It also handles data dumping when the reset button
* is pressed.
*
* Inputs: None
*
* Outputs: None
**********************************************************************************/
void mode_action(void)
{
int j;
int c = 0;
while(1)
{
if (mode > 2 )
{
if (u==0)
{
delay_ms(1000); //echo DS3234 output every second
delay_ms(1); //terminal would display 00FF00FFFF00 or 00FF00FFFFFF without this additional delay
readTime();
while (rtc_time[c] != '\0')
{
U1Write(rtc_time[c]);
c++;
}
c=0;
U1Write('\n');
}
}
else
{
if(log_array1 == 1)
{
stat(0,ON);
if(fat_write_file(handle,(unsigned char *)RX_array1, stringSize) < 0)
{
while(1)
{
stat(0,ON);
for(j = 0; j < 500000; j++);
stat(0,OFF);
stat(1,ON);
for(j = 0; j < 500000; j++);
stat(1,OFF);
}
}
sd_raw_sync();
stat(0,OFF);
log_array1 = 0;
}
if(log_array2 == 1)
{
stat(1,ON);
if(fat_write_file(handle,(unsigned char *)RX_array2, stringSize) < 0)
{
while(1)
{
stat(0,ON);
for(j = 0; j < 500000; j++);
stat(0,OFF);
stat(1,ON);
for(j = 0; j < 500000; j++);
stat(1,OFF);
}
}
sd_raw_sync();
stat(1,OFF);
log_array2 = 0;
}
if((IOPIN0 & 0x00000008) == 0) // if button pushed, log file & quit
{
VICIntEnClr = 0xFFFFFFFF;
if(RX_in < BUF_SIZE)
{
fat_write_file(handle, (unsigned char *)RX_array1, RX_in);
sd_raw_sync();
}
else if(RX_in >= BUF_SIZE)
{
fat_write_file(handle, (unsigned char *)RX_array2, RX_in - BUF_SIZE);
sd_raw_sync();
}
while(1)
{
stat(0,ON);
for(j = 0; j < 500000; j++);
stat(0,OFF);
stat(1,ON);
for(j = 0; j < 500000; j++);
stat(1,OFF);
}
}
}
}
}
/*******************************************************************************
* Function: test()
*
* Description: test is the routine that runs if the system is in test mode.
* Users can watch the ADC lines change slowly over UART0 at
* a rate of 9600 baud.
*
* Inputs: None
*
* Outputs: None
**********************************************************************************/
void test(void)
{
rprintf("\n\rLogomatic V2 Test Code:\n\r");
rprintf("ADC Test will begin in 5 seconds, hit stop button to terminate the test.\r\n\n");
delay_ms(5000);
while((IOPIN0 & 0x00000008) == 0x00000008)
{
// Get AD1.3
AD1CR = 0x0020FF08;
AD_conversion(1);
// Get AD0.3
AD0CR = 0x0020FF08;
AD_conversion(0);
// Get AD0.2
AD0CR = 0x0020FF04;
AD_conversion(0);
// Get AD0.1
AD0CR = 0x0020FF02;
AD_conversion(0);
// Get AD1.2
AD1CR = 0x0020FF04;
AD_conversion(1);
// Get AD0.4
AD0CR = 0x0020FF10;
AD_conversion(0);
// Get AD1.7
AD1CR = 0x0020FF80;
AD_conversion(1);
// Get AD1.6
AD1CR = 0x0020FF40;
AD_conversion(1);
delay_ms(1000);
rprintf("\n\r");
}
rprintf("\n\rTest complete, locking up...\n\r");
while(1);
}
/*******************************************************************************
* Function: AD_conversion(int regbank)
*
* Description: AD_conversion is the routine that digitizes analog data in
* in the register "regbank".
*
* Inputs: int regbank: register user wants to digitize data from
*
* Outputs: None
**********************************************************************************/
void AD_conversion(int regbank)
{
int temp = 0, temp2;
if(!regbank) // bank 0
{
AD0CR |= 0x01000000; // start conversion
while((temp & 0x80000000) == 0)
{
temp = AD0GDR;
}
temp &= 0x0000FFC0;
temp2 = temp / 0x00000040;
AD0CR = 0x00000000;
}
else // bank 1
{
AD1CR |= 0x01000000; // start conversion
while((temp & 0x80000000) == 0)
{
temp = AD1GDR;
}
temp &= 0x0000FFC0;
temp2 = temp / 0x00000040;
AD1CR = 0x00000000;
}
rprintf("%d", temp2);
rprintf(" ");
}
/*******************************************************************************
* Function: fat_initialize()
*
* Description: fat_initialize checks to see if the SD card was properly
* initialized, and if the root directory on the SD card is
* accessible.
*
* Inputs: None
*
* Outputs: None
**********************************************************************************/
void fat_initialize(void)
{
if(!sd_raw_init())
{
rprintf("SD Init Error\n\r");
while(1);
}
if(openroot())
{
rprintf("SD OpenRoot Error\n\r");
}
}
/*******************************************************************************
* Function: setTime(int d, int mo, int y, int h, int mi, int s)
*
* Description: setTime is the routine that sets the time in the RTC.
*
* Inputs: int d: day value to be set
* int mo: month value to be set
* int y: year value to be set
* int h: hour value to be set
* int mi: minute value to be set
* int s: seconds value to be set
*
* Outputs: None
**********************************************************************************/
void setTime(uint8_t d, uint8_t mo, uint8_t y, uint8_t h, uint8_t mi, uint8_t s)
{
uint8_t TimeDate [6]={s,mi,h,d,mo,y};
int v[6] = {0,1,2,4,5,6};
for(int i=0; i<6;i++){
select_ssp();
SPI1Send(v[i]+0x80);
SPI1Receive();
SPI1Send(TimeDate[i]);
SPI1Receive();
delay_ms(5);
unselect_ssp();
}
}
/*******************************************************************************
* Function: readTime();
*
* Description: readTime() uses spi communication to receive date information
* from the DS3234.
* The values of the DS3234 reads are. After the last read has been completed, the
* values are placed into a (uint8_t) array called rtc_time.
*
*
*
* Inputs: None
*
* Outputs: None
**********************************************************************************/
void readTime(void)
{
int i = 0;
uint8_t dummy;
uint8_t ss = 0;
uint8_t mm = 0;
uint8_t hh = 0;
uint8_t dd = 0;
uint8_t mo = 0;
uint8_t yy = 0;
int order[6] = {5,4,2,1,0,6}; //displays DS3234 time as YYMMDDhhmmss, may not be ncessary
for (i=0; i<6; i++)
{
select_ssp();
SPI1Send(order[i]+0x00);
SPI1Receive();
SPI1Send(order[i]+0x00);
dummy = SPI1Receive();
if (i == 0) {mo = dummy;}
else if (i == 1) {dd = dummy;}
else if (i==2) {hh = dummy;}
else if (i==3) {mm = dummy;}
else if (i==4) {ss = dummy;}
else if (i==5) {yy = dummy;}
delay_ms(10); //needed to properly read DS3234 time...not sure why
unselect_ssp();
}
string_printf((char *)rtc_time,"%02x%02x%02x%02x%02x%02x",mo,dd,hh,mm,ss,yy); //sets time as YYMMDDhhmmss
}
/*******************************************************************************
* Function: RTC_Init()
*
* Description: RTC_Init initializes the RTC.
*
* Inputs: None
*
* Outputs: None
**********************************************************************************/
void RTC_Init(void)
{
//set control register
select_ssp();
SPI1Send(0x8E);
SPI1Receive();
SPI1Send(0x60); //60= disable Osciallator and Battery SQ wave @1hz, temp compensation, Alarms disabled
SPI1Receive();
delay_ms(10); //needed to properly read DS3234 time...not sure why
unselect_ssp();
//delay_ms(10);
}
/*******************************************************************************
* Function: U1Read()
*
* Description: U1Read reads a byte of data from UART1 port.
*
* Inputs: None
*
* Outputs: char (1 byte of data)
**********************************************************************************/
char U1Read(void)
{
while( !(U1LSR & RDR)); // wait for data to arrive in FIFO
return U1RBR;
}
/*******************************************************************************
* Function: U1Write(char data)
*
* Description: U1Write writes a byte of data over UART1 port.
*
* Inputs: char data: data to be send over UART1 port
*
* Outputs: None
**********************************************************************************/
void U1Write(char data)
{
while (!(U1LSR & THRE)); // wait for THR to be emtpy
U1THR = data;
}
/*******************************************************************************
* Function: modulo(int num, int div)
*
* Description: modulo returns the remainder of the quotient num / div
*
* Inputs: int num: numerator
* int div: denominator
*
* Outputs: int (the remiainder)
**********************************************************************************/
int modulo(int num, int div)
{
while (num >= div) num -= div;
return num;
}
uint8_t uint2bcd(uint8_t ival)
{
return ((ival/10)<<4) | (modulo(ival,10));
}