Changeset - e70ab4bd3445
[Not reviewed]
default
0 3 0
mkanning@CL-SEC241-10.cedarville.edu - 13 years ago 2012-11-08 11:54:46
mkanning@CL-SEC241-10.cedarville.edu
Finished first pass on SD Card communication
3 files changed with 33 insertions and 51 deletions:
0 comments (0 inline, 0 general)
master/master/lib/logger.c
Show inline comments
 
/*
 
 * CFile1.c
 
 *
 
 * Created: 11/7/2012 8:05:44 PM
 
 *  Author: mkanning
 
 */ 
 
 
#include <string.h>
 
#include <avr/pgmspace.h>
 
#include <avr/sleep.h>
 
#include "sd/fat.h"
 
#include "sd/fat_config.h"
 
#include "sd/partition.h"
 
#include "sd/sd_raw.h"
 
#include "sd/sd_raw_config.h"
 
#include "logger.h"
 
 
/* 
 
	//console prompts and responses
 
 * I implemented an example application providing a simple command prompt which is accessible
 
 * via the UART at 9600 Baud. With commands similiar to the Unix shell you can browse different
 
 * directories, read and write files, create new ones and delete them again. Not all commands are
 
 * available in all software configurations.
 
 * - <tt>cat \<file\></tt>\n
 
 *   Writes a hexdump of \<file\> to the terminal.
 
 * - <tt>cd \<directory\></tt>\n
 
 *   Changes current working directory to \<directory\>.
 
 * - <tt>disk</tt>\n
 
 *   Shows card manufacturer, status, filesystem capacity and free storage space.
 
 * - <tt>init</tt>\n
 
 *   Reinitializes and reopens the memory card.
 
 * - <tt>ls</tt>\n
 
 *   Shows the content of the current directory.
 
 * - <tt>mkdir \<directory\></tt>\n
 
 *   Creates a directory called \<directory\>.
 
 * - <tt>mv \<file\> \<file_new\></tt>\n
 
 *   Renames \<file\> to \<file_new\>.
 
 * - <tt>rm \<file\></tt>\n
 
 *   Deletes \<file\>.
 
 * - <tt>sync</tt>\n
 
 *   Ensures all buffered data is written to the card.
 
 * - <tt>touch \<file\></tt>\n
 
 *   Creates \<file\>.
 
 * - <tt>write \<file\> \<offset\></tt>\n
 
 *   Writes text to \<file\>, starting from \<offset\>. The text is read
 
 *   from the UART, line by line. Finish with an empty line.
 
 
 
	//config edits
 
  * By changing the MCU* variables in the Makefile, you can use other Atmel
 
  * microcontrollers or different clock speeds. You might also want to change
 
  * the configuration defines in the files fat_config.h, partition_config.h,
 
  * sd_raw_config.h and sd-reader_config.h. For example, you could disable
 
  * write support completely if you only need read support.
 

	
 
 */
 
 
void logger_setup()
 
{
 
	while(1)
 
	{
 
		//check for sd exist/power/ready
 
		/* setup sd card slot */
 
		if(!sd_raw_init()) //sd_raw.c
 
		{
 
				#if DEBUG
 
		uart_puts_p(PSTR("MMC/SD initialization failed\n"));
 
			#endif
 
			continue;
 
		}
 
	
 
	
 
		//create partition BEGIN
 
		/* open first partition */ 
 
		struct partition_struct* partition = partition_open(sd_raw_read,
 
															sd_raw_read_interval,
 
	#if SD_RAW_WRITE_SUPPORT //probably want this to be true ??
 
															sd_raw_write,
 
															sd_raw_write_interval,
 
	#else
 
															0,
 
															0,
 
	#endif
 
															0
 
															);
 
		//check that partition was created correctly
 
		if(!partition)
 
		{
 
			/* If the partition did not open, assume the storage device
 
				* is a "superfloppy", i.e. has no MBR.
 
				*/
 
			partition = partition_open(sd_raw_read,
 
										sd_raw_read_interval,
 
	#if SD_RAW_WRITE_SUPPORT //probably want this to be true ??
 
										sd_raw_write,
 
										sd_raw_write_interval,
 
@@ -124,97 +95,97 @@ void logger_setup()
 
	
 
	
 
		//open directory BEGIN
 
		/* open root directory */
 
		struct fat_dir_entry_struct directory;
 
		fat_get_dir_entry_of_path(fs, "/", &directory);
 

	
 
		struct fat_dir_struct* dd = fat_open_dir(fs, &directory);
 
		if(!dd)
 
		{
 
			#if DEBUG
 
			uart_puts_p(PSTR("opening root directory failed\n"));
 
			#endif
 
			continue;
 
		}
 
		//open directory END
 
		
 
		
 
		//simplified version of console BEGIN
 
		/* provide a simple shell */
 
		char buffer[24];
 
		while(1)
 
		{
 
			/* execute command */
 
			/* search file in current directory and open it */
 
			struct fat_file_struct* fd = open_file_in_dir(fs, dd, "data.csv"); //logger.h
 
			if(!fd)
 
			{
 
				//error open file handling
 
				continue;
 
			}
 

	
 
			int32_t offset = 5;//strtolong(offset_value);
 
			if(!fat_seek_file(fd, &offset, FAT_SEEK_SET)) //seek to begin or end or what ??
 
			{
 
				//error seek to file handling
 
				
 
				fat_close_file(fd);
 
				continue;
 
			}
 

	
 
			/* read text from the shell and write it to the file */
 
			uint8_t data_len;
 
			while(1)
 
			{
 
				/* write text to file !! */
 
				if(fat_write_file(fd, (uint8_t*) buffer, data_len) != data_len)
 
				{
 
					uart_puts_p(PSTR("error writing to file\n"));
 
					//uart_puts_p(PSTR("error writing to file\n"));
 
					break;
 
				}
 
			}
 

	
 
			fat_close_file(fd); //may want to leave file open ??
 
		}
 
		//simplified version of console END	
 
		
 
		
 
		//prepare for closing SD connection BEGIN
 
		/* close directory */
 
		fat_close_dir(dd); //fat.c
 

	
 
		/* close file system */
 
		fat_close(fs); //fat.c
 

	
 
		/* close partition */
 
		partition_close(partition); //partition.c
 
		//prepare for closing SD connection END
 
 
	}
 
}	
 
 
//writes a single line to the SD card
 
uint8_t logger_writeLine(char* dateLine, uint8_t length)
 
{
 
	
 
}
 
 
//i think opens a file so it can be read/written
 
struct fat_file_struct* open_file_in_dir(struct fat_fs_struct* fs, struct fat_dir_struct* dd, const char* name)
 
{
 
	struct fat_dir_entry_struct file_entry;
 
	if(!find_file_in_dir(fs, dd, name, &file_entry))
 
	return 0;
 

	
 
	return fat_open_file(fs, &file_entry); //fat.h
 
}
 

	
 
//i think searches for a file
 
uint8_t find_file_in_dir(struct fat_fs_struct* fs, struct fat_dir_struct* dd, const char* name, struct fat_dir_entry_struct* dir_entry)
 
{
 
	while(fat_read_dir(dd, dir_entry))
 
	{
 
		if(strcmp(dir_entry->long_name, name) == 0)
 
		{
 
			fat_reset_dir(dd);
 
			return 1;
master/master/lib/sd/sd_raw.c
Show inline comments
 

	
 
/*
 
 * Copyright (c) 2006-2012 by Roland Riegel <feedback@roland-riegel.de>
 
 *
 
 * This file is free software; you can redistribute it and/or modify
 
 * it under the terms of either the GNU General Public License version 2
 
 * or the GNU Lesser General Public License version 2.1, both as
 
 * published by the Free Software Foundation.
 
 */
 

	
 
#include <string.h>
 
#include <avr/io.h>
 
#include "sd_raw.h"
 
#include "sd_raw_config.h"
 

	
 
/**
 
 * \addtogroup sd_raw MMC/SD/SDHC card raw access
 
 *
 
 * This module implements read and write access to MMC, SD
 
 * and SDHC cards. It serves as a low-level driver for the
 
 * higher level modules such as partition and file system
 
 * access.
 
 *
 
 * @{
 
 */
 
/**
 
 * \file
 
 * MMC/SD/SDHC raw access implementation (license: GPLv2 or LGPLv2.1)
 
 *
 
 * \author Roland Riegel
 
 */
 

	
 
/**
 
 * \addtogroup sd_raw_config MMC/SD configuration
 
 * Preprocessor defines to configure the MMC/SD support.
 
 */
 

	
 
/**
 
 * @}
 
 */
 

	
 
/* commands available in SPI mode */
 

	
 
/* CMD0: response R1 */
 
#define CMD_GO_IDLE_STATE 0x00
 
/* CMD1: response R1 */
 
#define CMD_SEND_OP_COND 0x01
 
/* CMD8: response R7 */
 
#define CMD_SEND_IF_COND 0x08
 
/* CMD9: response R1 */
 
#define CMD_SEND_CSD 0x09
 
/* CMD10: response R1 */
 
#define CMD_SEND_CID 0x0a
 
/* CMD12: response R1 */
 
#define CMD_STOP_TRANSMISSION 0x0c
 
/* CMD13: response R2 */
 
#define CMD_SEND_STATUS 0x0d
 
/* CMD16: arg0[31:0]: block length, response R1 */
 
#define CMD_SET_BLOCKLEN 0x10
 
/* CMD17: arg0[31:0]: data address, response R1 */
 
#define CMD_READ_SINGLE_BLOCK 0x11
 
/* CMD18: arg0[31:0]: data address, response R1 */
 
@@ -139,105 +140,105 @@
 
#define DR_STATUS_CRC_ERR 0x0a
 
#define DR_STATUS_WRITE_ERR 0x0c
 

	
 
/* status bits for card types */
 
#define SD_RAW_SPEC_1 0
 
#define SD_RAW_SPEC_2 1
 
#define SD_RAW_SPEC_SDHC 2
 

	
 
#if !SD_RAW_SAVE_RAM
 
/* static data buffer for acceleration */
 
static uint8_t raw_block[512];
 
/* offset where the data within raw_block lies on the card */
 
static offset_t raw_block_address;
 
#if SD_RAW_WRITE_BUFFERING
 
/* flag to remember if raw_block was written to the card */
 
static uint8_t raw_block_written;
 
#endif
 
#endif
 

	
 
/* card type state */
 
static uint8_t sd_raw_card_type;
 

	
 
/* private helper functions */
 
static void sd_raw_send_byte(uint8_t b);
 
static uint8_t sd_raw_rec_byte();
 
static uint8_t sd_raw_send_command(uint8_t command, uint32_t arg);
 

	
 
/**
 
 * \ingroup sd_raw
 
 * Initializes memory card communication.
 
 *
 
 * \returns 0 on failure, 1 on success.
 
 */
 
uint8_t sd_raw_init()
 
{
 
    /* enable inputs for reading card status */
 
    configure_pin_available();
 
    configure_pin_locked();
 

	
 
    /* enable outputs for MOSI, SCK, SS, input for MISO */
 
    configure_pin_mosi();
 
    configure_pin_sck();
 
    configure_pin_ss();
 
    configure_pin_miso();
 

	
 
    unselect_card();
 

	
 
    /* initialize SPI with lowest frequency; max. 400kHz during identification mode of card */
 
    SPCR = (0 << SPIE) | /* SPI Interrupt Enable */
 
           (1 << SPE)  | /* SPI Enable */
 
           (0 << DORD) | /* Data Order: MSB first */
 
           (1 << MSTR) | /* Master mode */
 
           (0 << CPOL) | /* Clock Polarity: SCK low when idle */
 
           (0 << CPHA) | /* Clock Phase: sample on rising SCK edge */
 
           (1 << SPR1) | /* Clock Frequency: f_OSC / 128 */
 
           (1 << SPR0);
 
    SPSR &= ~(1 << SPI2X); /* No doubled clock frequency */
 
    SPCR0 = (0 << SPIE0) | /* SPI Interrupt Enable */
 
           (1 << SPE0)  | /* SPI Enable */
 
           (0 << DORD0) | /* Data Order: MSB first */
 
           (1 << MSTR0) | /* Master mode */
 
           (0 << CPOL0) | /* Clock Polarity: SCK low when idle */
 
           (0 << CPHA0) | /* Clock Phase: sample on rising SCK edge */
 
           (1 << SPR10) | /* Clock Frequency: f_OSC / 128 */
 
           (1 << SPR00);
 
    SPSR0 &= ~(1 << SPI2X0); /* No doubled clock frequency */
 

	
 
    /* initialization procedure */
 
    sd_raw_card_type = 0;
 
    
 
    if(!sd_raw_available())
 
        return 0;
 

	
 
    /* card needs 74 cycles minimum to start up */
 
    for(uint8_t i = 0; i < 10; ++i)
 
    {
 
        /* wait 8 clock cycles */
 
        sd_raw_rec_byte();
 
    }
 

	
 
    /* address card */
 
    select_card();
 

	
 
    /* reset card */
 
    uint8_t response;
 
    for(uint16_t i = 0; ; ++i)
 
    {
 
        response = sd_raw_send_command(CMD_GO_IDLE_STATE, 0);
 
        if(response == (1 << R1_IDLE_STATE))
 
            break;
 

	
 
        if(i == 0x1ff)
 
        {
 
            unselect_card();
 
            return 0;
 
        }
 
    }
 

	
 
#if SD_RAW_SDHC
 
    /* check for version of SD card specification */
 
    response = sd_raw_send_command(CMD_SEND_IF_COND, 0x100 /* 2.7V - 3.6V */ | 0xaa /* test pattern */);
 
    if((response & (1 << R1_ILL_COMMAND)) == 0)
 
    {
 
        sd_raw_rec_byte();
 
        sd_raw_rec_byte();
 
        if((sd_raw_rec_byte() & 0x01) == 0)
 
            return 0; /* card operation voltage range doesn't match */
 
        if(sd_raw_rec_byte() != 0xaa)
 
            return 0; /* wrong test pattern */
 

	
 
        /* card conforms to SD 2 card specification */
 
        sd_raw_card_type |= (1 << SD_RAW_SPEC_2);
 
    }
 
    else
 
@@ -269,164 +270,164 @@ uint8_t sd_raw_init()
 
#endif
 
            sd_raw_send_command(CMD_APP, 0);
 
            response = sd_raw_send_command(CMD_SD_SEND_OP_COND, arg);
 
        }
 
        else
 
        {
 
            response = sd_raw_send_command(CMD_SEND_OP_COND, 0);
 
        }
 

	
 
        if((response & (1 << R1_IDLE_STATE)) == 0)
 
            break;
 

	
 
        if(i == 0x7fff)
 
        {
 
            unselect_card();
 
            return 0;
 
        }
 
    }
 

	
 
#if SD_RAW_SDHC
 
    if(sd_raw_card_type & (1 << SD_RAW_SPEC_2))
 
    {
 
        if(sd_raw_send_command(CMD_READ_OCR, 0))
 
        {
 
            unselect_card();
 
            return 0;
 
        }
 

	
 
        if(sd_raw_rec_byte() & 0x40)
 
            sd_raw_card_type |= (1 << SD_RAW_SPEC_SDHC);
 

	
 
        sd_raw_rec_byte();
 
        sd_raw_rec_byte();
 
        sd_raw_rec_byte();
 
    }
 
#endif
 

	
 
    /* set block size to 512 bytes */
 
    if(sd_raw_send_command(CMD_SET_BLOCKLEN, 512))
 
    {
 
        unselect_card();
 
        return 0;
 
    }
 

	
 
    /* deaddress card */
 
    unselect_card();
 

	
 
    /* switch to highest SPI frequency possible */
 
    SPCR &= ~((1 << SPR1) | (1 << SPR0)); /* Clock Frequency: f_OSC / 4 */
 
    SPSR |= (1 << SPI2X); /* Doubled Clock Frequency: f_OSC / 2 */
 
    SPCR0 &= ~((1 << SPR10) | (1 << SPR00)); /* Clock Frequency: f_OSC / 4 */
 
    SPSR0 |= (1 << SPI2X0); /* Doubled Clock Frequency: f_OSC / 2 */
 

	
 
#if !SD_RAW_SAVE_RAM
 
    /* the first block is likely to be accessed first, so precache it here */
 
    raw_block_address = (offset_t) -1;
 
#if SD_RAW_WRITE_BUFFERING
 
    raw_block_written = 1;
 
#endif
 
    if(!sd_raw_read(0, raw_block, sizeof(raw_block)))
 
        return 0;
 
#endif
 

	
 
    return 1;
 
}
 

	
 
/**
 
 * \ingroup sd_raw
 
 * Checks wether a memory card is located in the slot.
 
 *
 
 * \returns 1 if the card is available, 0 if it is not.
 
 */
 
uint8_t sd_raw_available()
 
{
 
    return get_pin_available() == 0x00;
 
}
 

	
 
/**
 
 * \ingroup sd_raw
 
 * Checks wether the memory card is locked for write access.
 
 *
 
 * \returns 1 if the card is locked, 0 if it is not.
 
 */
 
uint8_t sd_raw_locked()
 
{
 
    return get_pin_locked() == 0x00;
 
}
 

	
 
/**
 
 * \ingroup sd_raw
 
 * Sends a raw byte to the memory card.
 
 *
 
 * \param[in] b The byte to sent.
 
 * \see sd_raw_rec_byte
 
 */
 
void sd_raw_send_byte(uint8_t b)
 
{
 
    SPDR = b;
 
    SPDR0 = b;
 
    /* wait for byte to be shifted out */
 
    while(!(SPSR & (1 << SPIF)));
 
    SPSR &= ~(1 << SPIF);
 
    while(!(SPSR0 & (1 << SPIF0)));
 
    SPSR0 &= ~(1 << SPIF0);
 
}
 

	
 
/**
 
 * \ingroup sd_raw
 
 * Receives a raw byte from the memory card.
 
 *
 
 * \returns The byte which should be read.
 
 * \see sd_raw_send_byte
 
 */
 
uint8_t sd_raw_rec_byte()
 
{
 
    /* send dummy data for receiving some */
 
    SPDR = 0xff;
 
    while(!(SPSR & (1 << SPIF)));
 
    SPSR &= ~(1 << SPIF);
 
    SPDR0 = 0xff;
 
    while(!(SPSR0 & (1 << SPIF0)));
 
    SPSR0 &= ~(1 << SPIF0);
 

	
 
    return SPDR;
 
    return SPDR0;
 
}
 

	
 
/**
 
 * \ingroup sd_raw
 
 * Send a command to the memory card which responses with a R1 response (and possibly others).
 
 *
 
 * \param[in] command The command to send.
 
 * \param[in] arg The argument for command.
 
 * \returns The command answer.
 
 */
 
uint8_t sd_raw_send_command(uint8_t command, uint32_t arg)
 
{
 
    uint8_t response;
 

	
 
    /* wait some clock cycles */
 
    sd_raw_rec_byte();
 

	
 
    /* send command via SPI */
 
    sd_raw_send_byte(0x40 | command);
 
    sd_raw_send_byte((arg >> 24) & 0xff);
 
    sd_raw_send_byte((arg >> 16) & 0xff);
 
    sd_raw_send_byte((arg >> 8) & 0xff);
 
    sd_raw_send_byte((arg >> 0) & 0xff);
 
    switch(command)
 
    {
 
        case CMD_GO_IDLE_STATE:
 
           sd_raw_send_byte(0x95);
 
           break;
 
        case CMD_SEND_IF_COND:
 
           sd_raw_send_byte(0x87);
 
           break;
 
        default:
 
           sd_raw_send_byte(0xff);
 
           break;
 
    }
 
    
 
    /* receive response */
 
    for(uint8_t i = 0; i < 10; ++i)
 
    {
 
        response = sd_raw_rec_byte();
 
        if(response != 0xff)
 
            break;
 
    }
 

	
 
    return response;
 
}
 

	
 
/**
master/master/lib/sd/sd_raw_config.h
Show inline comments
 
@@ -61,79 +61,89 @@ extern "C"
 
/**
 
 * \ingroup sd_raw_config
 
 * Controls support for SDHC cards.
 
 *
 
 * Set to 1 to support so-called SDHC memory cards, i.e. SD
 
 * cards with more than 2 gigabytes of memory.
 
 */
 
#define SD_RAW_SDHC 0
 

	
 
/**
 
 * @}
 
 */
 

	
 
/* defines for customisation of sd/mmc port access */
 
#if defined(__AVR_ATmega8__) || \
 
    defined(__AVR_ATmega48__) || \
 
    defined(__AVR_ATmega48P__) || \
 
    defined(__AVR_ATmega88__) || \
 
    defined(__AVR_ATmega88P__) || \
 
    defined(__AVR_ATmega168__) || \
 
    defined(__AVR_ATmega168P__) || \
 
    defined(__AVR_ATmega328P__)
 
    #define configure_pin_mosi() DDRB |= (1 << DDB3)
 
    #define configure_pin_sck() DDRB |= (1 << DDB5)
 
    #define configure_pin_ss() DDRB |= (1 << DDB2)
 
    #define configure_pin_miso() DDRB &= ~(1 << DDB4)
 

	
 
    #define select_card() PORTB &= ~(1 << PORTB2)
 
    #define unselect_card() PORTB |= (1 << PORTB2)
 
#elif defined(__AVR_ATmega16__) || \
 
      defined(__AVR_ATmega32__)
 
    #define configure_pin_mosi() DDRB |= (1 << DDB5)
 
    #define configure_pin_sck() DDRB |= (1 << DDB7)
 
    #define configure_pin_ss() DDRB |= (1 << DDB4)
 
    #define configure_pin_miso() DDRB &= ~(1 << DDB6)
 

	
 
    #define select_card() PORTB &= ~(1 << PORTB4)
 
    #define unselect_card() PORTB |= (1 << PORTB4)
 
#elif defined(__AVR_ATmega64__) || \
 
      defined(__AVR_ATmega128__) || \
 
      defined(__AVR_ATmega169__)
 
    #define configure_pin_mosi() DDRB |= (1 << DDB2)
 
    #define configure_pin_sck() DDRB |= (1 << DDB1)
 
    #define configure_pin_ss() DDRB |= (1 << DDB0)
 
    #define configure_pin_miso() DDRB &= ~(1 << DDB3)
 

	
 
    #define select_card() PORTB &= ~(1 << PORTB0)
 
    #define unselect_card() PORTB |= (1 << PORTB0)
 
#elif defined(__AVR_ATmega164P__) || \
 
	  defined(__AVR_ATmega324P__) || \
 
	  defined(__AVR_ATmega664P__)
 
    #define configure_pin_mosi() DDRB |= (1 << DDRB5) //PB5
 
    #define configure_pin_sck() DDRB |= (1 << DDRB7) //PB7
 
    #define configure_pin_ss() DDRB |= (1 << DDRB0) //PB0 - custom pin
 
    #define configure_pin_miso() DDRB &= ~(1 << DDRB6) //PB6
 
	
 
    #define select_card() PORTB &= ~(1 << PORTB0)
 
    #define unselect_card() PORTB |= (1 << PORTB0)
 
#else
 
    //#error "no sd/mmc pin mapping available!" //commented out due to build error ??
 
    #error "no sd/mmc pin mapping available!" //sends error if micro not specified
 
#endif
 

	
 
#define configure_pin_available() DDRC &= ~(1 << DDC4)
 
#define configure_pin_locked() DDRC &= ~(1 << DDC5)
 
#define configure_pin_available() DDRC &= ~(1 << DDRC4)
 
#define configure_pin_locked() DDRC &= ~(1 << DDRC5)
 

	
 
#define get_pin_available() (PINC & (1 << PINC4))
 
#define get_pin_locked() (PINC & (1 << PINC5))
 

	
 
#if SD_RAW_SDHC
 
    typedef uint64_t offset_t;
 
#else
 
    typedef uint32_t offset_t;
 
#endif
 

	
 
/* configuration checks */
 
#if SD_RAW_WRITE_SUPPORT
 
#undef SD_RAW_SAVE_RAM
 
#define SD_RAW_SAVE_RAM 0
 
#else
 
#undef SD_RAW_WRITE_BUFFERING
 
#define SD_RAW_WRITE_BUFFERING 0
 
#endif
 

	
 
#ifdef __cplusplus
 
}
 
#endif
 

	
 
#endif
 

	
0 comments (0 inline, 0 general)