EVK1100: Writing to SD/MMC and LCD display - problem solved

Go To Last Post
18 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

My SD/MMC memory cards were very error-prone until I realized that the memory card was sensitive to the SPI traffic even when CS line was not active. Especially so on two conditions:
* initialization,
* writing.

After adding 'wait for memcard to become not busy' after writing and before LCD activity the problem went away.

It looks like the problem is solved for now. While I am not sure if I have hit the right nail, perhaps it might be useful for somebody.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

What makes me a very pathetic hardware debugger is the fact that I have been overlooking SD/MMC card initial synchronization (74 bits of 1's). Very stupid of me. Writing/reading ten 0xFF-s works only if some other CS line except the SD/MMC cards one is activated. A DIP204 CS line will do.

Hopefully all quirks of SD/MMC and LCD on the EVK1100 have been covered by now..

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi! I have a question for using LCD and SD card the same time. They works with SPI clock very different. Should I reinitialize SPI every times I have to write to LCD or SD-card? Is there any efficient way to do it? The problem is big for me, Sd and LCD are randomly activated by interrupts...
Thanks

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You have a divider per chip select, take a look at SPI chip select register.

Hans-Christian

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Do you mean by 'activating' that you are writing to SD card / Display in the interrupt service routines?

I usually keep ISR-s very short - they only stuff queues - and let the main loop do the real work. So far it has been bulletproof approach.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes, I have a main loop that saves a buffer (fillen by one TimerCounter ISR that runs every ms) to SD. In addition to this I have a gpio interrupt that manage the user interface (buttons/display)...Isn't it a good approach?
Returning to my problem, I don't know how to edit sd routines as you have done...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I post my code, hoping someone could help me:

sd_mmc_init(spiOptionsSD, PBA_HZ);	
while (sd_mmc_mem_check()!=OK);

if ((sd_mmc_init(spiOptionsSD, PBA_HZ))!=1)
    return (ERROR_9);
spi_initMaster(DIP204_SPI, &spiOptions);
spi_selectionMode(DIP204_SPI, 0, 0, 0);
spi_enable(DIP204_SPI);
spi_setupChipReg(DIP204_SPI, &spiOptions, FOSC0);
dip204_init(0);		//Set backlight on, not PWM backlighted
b_fsaccess_init();
if ((fd1 = open("file1.dat", O_RDONLY)) < 0)
   return (ERROR_8);
file_size=fsaccess_file_get_size(fd1);

The program frezees in the open function...
Note that it work if I'm not using the display...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

My code is written in C++ I guess and although it contains some of the framework code, it has been extensively modified. Probably it will only cause confusion.

However, I extracted the relevant parts.

1. SPI initialization, this is merged for both SD/MMC and display:

/** Initialize SPI interfaces for both LCD and SD/MMC.
 */
static void
spi_init()
{
	tprintf("spi...");
	static const gpio_map_t DIP204_SPI_GPIO_MAP =
	{
		{DIP204_SPI_SCK_PIN,  DIP204_SPI_SCK_FUNCTION },  // SPI Clock.
		{DIP204_SPI_MISO_PIN, DIP204_SPI_MISO_FUNCTION},  // MISO.
		{DIP204_SPI_MOSI_PIN, DIP204_SPI_MOSI_FUNCTION},  // MOSI.
		{DIP204_SPI_NPCS_PIN, DIP204_SPI_NPCS_FUNCTION},  // Chip Select NPCS.
		{SD_MMC_SPI_NPCS_PIN, SD_MMC_SPI_NPCS_FUNCTION}   // Chip Select NPCS.
	};

	// add the spi options driver structure for the LCD DIP204
	spi_options_t spiOptions;
	spiOptions.reg          = DIP204_SPI_CS;
	spiOptions.baudrate     = 6*1000000;
	spiOptions.bits         = 8;
	spiOptions.spck_delay   = 0;
	spiOptions.trans_delay  = 0;
	spiOptions.stay_act     = 1;
	spiOptions.spi_mode     = 0;
	spiOptions.fdiv         = 0;
	spiOptions.modfdis      = 1;

	// Assign I/Os to SPI
	gpio_enable_module(DIP204_SPI_GPIO_MAP, sizeof(DIP204_SPI_GPIO_MAP) / sizeof(DIP204_SPI_GPIO_MAP[0]));

	// Initialize as master
	spi_initMaster(DIP204_SPI, &spiOptions);

	// Set selection mode: variable_ps, pcs_decode, delay
	spi_selectionMode(DIP204_SPI, 0, 0, 0);

	// Enable SPI
	spi_enable(DIP204_SPI);

	// setup chip registers
	spi_setupChipReg(DIP204_SPI, &spiOptions, F_PBA);
	spiOptions.reg = 1;	// SD_MMC CS
	spi_setupChipReg(SD_MMC_SPI, &spiOptions, F_PBA);

	// Unselect the card and the display.
	spi_unselectChip(SD_MMC_SPI, 1);
	spi_unselectChip(DIP204_SPI, DIP204_SPI_CS);

	tprintf(" done.\n");
}

2. SD/MMC synchronization:

	// Atmel EVK1100 specific :(
	// Synchronize the memory card. The following is required:
	// 1. CS line of SD/MMC is NOT selected!
	// 2. Atmel SPI interface requires at least one CS line to be selected in order to output any data.
	// The LCD display loses. I am very sorry. Hopefully she is not angry at me.
	spi_selectChip(DIP204_SPI, DIP204_SPI_CS);
	for (unsigned int i=0; i<10; ++i) {
		r1 = send_and_read(0xFF);
	}
	spi_unselectChip(DIP204_SPI, DIP204_SPI_CS);

SD/MMC synchronization has to be run on two occasions:
1. startup, before any display initialization, otherwise the card might be ruined.
2. any reinitialization of the SD/MMC card.

As you can see, I run the SD/MMC and display at the same speed. I haven't tested different speeds.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

There were also some issues with the FAT library present in the Framework which have already been discussed in this forum. A simple search should find them.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for your informations...I'm trying your suggested code, but I can't make it work...Damn...
Haven't you got any working complete example to show me?
Thanks again

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Unfortunately I don't have any sample code except the one given above.

The code I posted is from a working application and. Since you gave me no clue as to why my code doesn't work I cannot help but repeat in vain, maybe it helps:
1. The startup code goes as follows:
1.1. SPI initialization for both SD and Display.
1.2. Emit SD synchronization sequence
1.3. Initialize Display library.
1.4. Initialize SD library
2. Use both as you wish.

By the way, did you find the SD/FAT library issues which have been discussed before?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi, thank you for your replies.
As you have understood I'm a newbie with SPI and SD cards.
I've not found the FAT issues you're speaking about yet, but FAT isn't a problem for now (it will be the next weeks :-)). At the moment my difficulties are related to a more low level problem (I'm still initializing SD and Display).
I'm using Atmel BETA sd-mmc driver (I link them here http://www.megaupload.com/?d=EKS...). I don't know if they are bugged or not.
I haven't emitted the SD sincro sequence, I think it's contained in sd_mmc_init(). I've added the suggested sync sequence before sd and display inizialization (is it correct?)
I've tried to make a program following your guidelines, but I can't make it work.

This is the code:

void andreie_sync(void)
   {
   	int r1,i;
	unsigned short data_read;
   spi_selectChip(DIP204_SPI, DIP204_SPI_CS);
   for (i=0; i<10; ++i)
   		{
      	spi_write(&AVR32_SPI1,data_to_send);
		spi_read(&AVR32_SPI1,&data_read);
  		}
   spi_unselectChip(DIP204_SPI, DIP204_SPI_CS); 
   }

int main(void)
{
	
	static const gpio_map_t DIP204_SPI_GPIO_MAP =
   {
      {DIP204_SPI_SCK_PIN,  DIP204_SPI_SCK_FUNCTION },  // SPI Clock.
      {DIP204_SPI_MISO_PIN, DIP204_SPI_MISO_FUNCTION},  // MISO.
      {DIP204_SPI_MOSI_PIN, DIP204_SPI_MOSI_FUNCTION},  // MOSI.
      {DIP204_SPI_NPCS_PIN, DIP204_SPI_NPCS_FUNCTION},  // Chip Select NPCS.
      {SD_MMC_SPI_NPCS_PIN, SD_MMC_SPI_NPCS_FUNCTION}   // Chip Select NPCS.
   }; 
	
	
	spi_options_t spiOptions;
   spiOptions.reg          = DIP204_SPI_CS;
   spiOptions.baudrate     = 6*1000000;
   spiOptions.bits         = 8;
   spiOptions.spck_delay   = 0;
   spiOptions.trans_delay  = 0;
   spiOptions.stay_act     = 1;
   spiOptions.spi_mode     = 0;
   spiOptions.fdiv         = 0;
   spiOptions.modfdis      = 1; 

	pm_switch_to_osc0(&AVR32_PM, FOSC0, OSC0_STARTUP);
	init_dbg_rs232(FOSC0);

   gpio_enable_module(DIP204_SPI_GPIO_MAP, sizeof(DIP204_SPI_GPIO_MAP) / sizeof(DIP204_SPI_GPIO_MAP[0]));
   spi_initMaster(DIP204_SPI, &spiOptions);
   spi_selectionMode(DIP204_SPI, 0, 0, 0);
   spi_enable(DIP204_SPI);
   spi_setupChipReg(DIP204_SPI, &spiOptions, FPBA);
   spiOptions.reg = 1;   // SD_MMC CS
   spi_setupChipReg(SD_MMC_SPI, &spiOptions, FPBA);
   spi_unselectChip(SD_MMC_SPI, 1);
   spi_unselectChip(DIP204_SPI, DIP204_SPI_CS); 


	andreie_sync();
	
	dip204_init(0); 
	dip204_set_cursor_position(1,1);
	dip204_write_string("Hello World!");
	
	print_dbg("Hello world!");

	
	andreie_sync();
	sd_mmc_init(spiOptions, PBA_HZ);
	while ( sd_mmc_mem_check() != OK );	

	dip204_set_cursor_position(1,2);
    dip204_write_string("SD init done");
  
	print_dbg("\nSd init done");
  
	while(1);
}

I can see "helloworld" on the display (and it's correctly trasmitted to usart), but I can't see "SD init done" (I can see it only on usart).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Your code is fine, there is only one fix missing.

I am very sorry for pointing at the FAT libraries... the culprit is in the SD functions, can be found by searching for "sd_mmc_init".

See this post by mandre.

P.S. in case you don't have JTAGICE mkII, the function "print_dbg", especially combined with "sprintf", can be useful for finding out where the code is stuck.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

andreie wrote:
Your code is fine, there is only one fix missing.
Hi, I can't understand what is the last thing missing. I've tried to compile mandre code but I've not solved my problem...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Did you compile it successfully?

Did you follow his suggestion to remove some code from the sd_mmc_init?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi andreie. Today I've a little progress. Now I am able to write on the display after Sd initialization. I've used mandre suggestions (used his code and commented out almost all sd_mmc_spi_init).
My code is this:

#include "evk1100.h"
#include "compiler.h"
#include "config.h"
#include "gpio.h" 
#include "pm.h" 
#include "usart.h"
#include "print_funcs.h"
#include "spi.h"
#include "dip204.h"
#include "sd_mmc.h"
#include "sd_mmc_mem.h"
#include "fsaccess.h"
#include 




static void init_spi_gpio()
{
  // GPIO map for SPI.
  static const gpio_map_t spi_gpio_map =
  {
    {AVR32_SPI1_SCK_0_PIN,          AVR32_SPI1_SCK_0_FUNCTION         },  // SPI Clock.
    {AVR32_SPI1_MISO_0_PIN,         AVR32_SPI1_MISO_0_FUNCTION        },  // MISO.
    {AVR32_SPI1_MOSI_0_PIN,         AVR32_SPI1_MOSI_0_FUNCTION        },  // MOSI.
    {AVR32_SPI1_NPCS_1_PIN,         AVR32_SPI1_NPCS_1_FUNCTION        },  // CS SD
  };
    
  gpio_enable_module(spi_gpio_map,sizeof(spi_gpio_map) / sizeof(spi_gpio_map[0]));
}



static void init_display(long hwclk)
{

   static const gpio_map_t spi_gpio_map =
  {
    {AVR32_SPI1_NPCS_2_PIN,         AVR32_SPI1_NPCS_2_FUNCTION        }   // Display
  };
 
  gpio_enable_module(spi_gpio_map, sizeof(spi_gpio_map) / sizeof(spi_gpio_map[0]));
           
  spi_options_t spiOptions =
  {
    .reg          = DIP204_SPI_CS,
    .baudrate     = 1000000,
    .bits         = 8,
    .spck_delay   = 0,
    .trans_delay  = 0,
    .stay_act     = 1,
    .spi_mode     = 0,
    .fdiv         = 0,
    .modfdis      = 1
  };

  
  spi_initMaster(DIP204_SPI, &spiOptions);
  spi_selectionMode(DIP204_SPI, 0, 0, 0);
  spi_enable(DIP204_SPI);
  spi_setupChipReg(DIP204_SPI, &spiOptions, hwclk);
}


static void sdcard_resources_init(long hwclk)
{
  static const gpio_map_t spi_gpio_map =
  {
    {AVR32_SPI1_NPCS_1_PIN,         AVR32_SPI1_NPCS_1_FUNCTION        }   // SD Card
  };
  
  gpio_enable_module(spi_gpio_map, sizeof(spi_gpio_map) / sizeof(spi_gpio_map[0]));
   
  spi_options_t spiOptions =
  {
    .reg          = 1,
    .baudrate     = 12000000, // Defined in conf_at45dbx.h
    .bits         = 8,         // Defined in conf_at45dbx.h
    .spck_delay   = 0,
    .trans_delay  = 0,
    .stay_act     = 1,
    .spi_mode     = 0,
    .fdiv         = 0,
    .modfdis      = 1
  };
 
 
  sd_mmc_init(spiOptions, hwclk);
  delay_ms(50);
 

	sd_mmc_test_unit_ready();


} 

				
int LoadSDMap()
{
	int fd1;
	int j;
	 char fd_char[10];
	b_fsaccess_init();

	print_dbg("\nFile descriptor: ");
	
	if ((fd1 = open("test.dat", O_RDONLY)) < 0)
		{
		sprintf( fd_char, "%d", fd1 );              
		print_dbg(fd_char);	 
		return 8;
		}
	sprintf( fd_char, "%d", fd1 );              
	print_dbg(fd_char);	 
    ...
	cut......
	...
	close(fd1);	
	return 0;
}



int main(void)
{
	
  pm_switch_to_osc0(&AVR32_PM, FOSC0, OSC0_STARTUP);
  init_dbg_rs232(FOSC0);
  print_dbg("\n\nTEST SD & DISPLAY\n");
 
  init_spi_gpio();
  init_display(FOSC0);

  dip204_set_cursor_position(1,1);
  dip204_write_string("Display init done");
  print_dbg("\nDisplay init done");
  
  sdcard_resources_init(FOSC0); 

  dip204_set_cursor_position(1,2);
  dip204_write_string("Sd init done");
  print_dbg("\nSd init done");

  LoadFile();
  
  while(1);
	
}

With this code now I can init Display & SD (I can correctly see two initialization messages displayed).
But now the open() function fails (it returns -1). Is it related with the fat issue you were speaking about (it is not clear to me this aspect)?
Now I am a lot confused also about the resincronization function you suggested the past days. Is it still necessary? Should I run it before "init_display(FOSC0)" and "sdcard_resources_init(FOSC0)" ?
Thanks again

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Good work!

Yes, it should be run before display and sdcard initialization. Otherwise the SD card might not start reliably.

As for why the open fails, I have no clue - I have never used it. I suggest to peek inside it and see where it stops. Probably there is a small detail overlooked.

I am sorry, it was my error to point at the FAT library. In reality the SD/MMC library was at fault.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok thanks! Very very kind! Now I'll make some investigation about open error...