Bit-bangind a TSOP-48 NAND Flash with the RPi


12 posts
by pharos » Sat Sep 08, 2012 12:15 pm
Hi,

I'm trying to bit-bang a 3.3V NAND Flash which has a very fine pitch (0.5mm) using a solderless clip called the 360 Clip. Although it was originally meant to hack game consoles (hence the name), I'm attempting to reuse it as a generic TSOP NAND reader/writer. The most interesting thing about this piece, in addition to being solderless, is the very low price as compared to commercial NAND programmers (which usually require desoldering the chip as well).

The following link has a full-resolution picture of my setup:

https://picasaweb.google.com/1078242449 ... 7118336754

So I don't have the original PSU for the board I'm using as a guinea pig, so I'm using the 3.3V from the RPi. I noticed when plugging the power other parts of the board come alive, leading to the RPi (sometimes) resetting do to overcurrent I suppose. I'm thinking this is causing the issue I'm having (not being able to talk to the flash at all, even READ ID doesn't produce a result, I keep reading all 0s). I've checked the timings, the wirings and my own C code multiple times. What do you think might be the problem?

For the reference, here's my test code (and yes, I did check it does correctly output 0s and 1s, and reading from the data lines also work).

Code: Select all
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <stdio.h>
#include <fcntl.h>

//#define DEBUG 1

#define BCM2708_PERI_BASE   0x20000000
#define GPIO_BASE       (BCM2708_PERI_BASE + 0x200000)

#define N_WRITE_PROTECT      0
#define N_WRITE_ENABLE       21
#define ADDRESS_LATCH_ENABLE   4
#define COMMAND_LATCH_ENABLE   17
#define N_READ_ENABLE      18
#define N_CHIP_ENABLE      22

int data_to_gpio_map[8] = { 23, 24, 25, 8, 7, 10, 9, 11 };

#define DIRECTION_DATA8_IN  1
#define DIRECTION_DATA8_OUT 2

volatile unsigned int *gpio;

inline void INP_GPIO(int g)
{
#ifdef DEBUG
   printf("setting direction of GPIO#%d to input\n", g);
#endif
   (*(gpio+((g)/10)) &= ~(7<<(((g)%10)*3)));
}

inline void OUT_GPIO(int g)
{
   INP_GPIO(g);
#ifdef DEBUG
   printf("setting direction of GPIO#%d to output\n", g);
#endif
   *(gpio+((g)/10)) |= (1<<(((g)%10)*3));
}

int current_data_direction = 0;

inline void GPIO_SET_1(int g)
{
#ifdef DEBUG
   printf("setting GPIO#%d to 1\n", g);
#endif
   *(gpio +  7)  = 1 << g;
}

inline void GPIO_SET_0(int g)
{
#ifdef DEBUG
   printf("setting GPIO#%d to 0\n", g);
#endif
   *(gpio + 10)  = 1 << g;
}

inline int GPIO_READ(int g)
{
   int x = (*(gpio + 13) & (1 << g)) >> g;
#ifdef DEBUG
   printf("GPIO#%d reads as %d\n", g, x);
#endif
   return x;
}

inline void set_data_direction_in(void)
{
   int i;
   if (current_data_direction != DIRECTION_DATA8_IN) {
#ifdef DEBUG
      printf("data direction => IN\n");
#endif
      for (i = 0; i < 8; i++)
         INP_GPIO(data_to_gpio_map[i]);
      current_data_direction = DIRECTION_DATA8_IN;
   }
}

inline void set_data_direction_out(void)
{
   int i;
   if (current_data_direction != DIRECTION_DATA8_OUT) {
#ifdef DEBUG
      printf("data direction => OUT\n");
#endif
      for (i = 0; i < 8; i++)
         OUT_GPIO(data_to_gpio_map[i]);
      current_data_direction = DIRECTION_DATA8_OUT;
   }
}

inline int GPIO_DATA8_IN(void)
{
   int i, data;
   for (i = data = 0; i < 8; i++, data = data << 1) {
      data |= GPIO_READ(data_to_gpio_map[7 - i]);
   }
   data >>= 1;
#ifdef DEBUG
   printf("GPIO_DATA8_OUT: data=%02x\n", data);
#endif
   return data;
}

inline void GPIO_DATA8_OUT(int data)
{
   int i;
#ifdef DEBUG
   printf("GPIO_DATA8_OUT: data=%02x\n", data);
#endif
   for (i = 0; i < 8; i++, data >>= 1) {
      if (data & 1)
         GPIO_SET_1(data_to_gpio_map[i]);
      else
         GPIO_SET_0(data_to_gpio_map[i]);
   }
}

int delay;
int shortpause()
{
   int i;
   volatile static int dontcare = 0;
   for (i = 0; i < delay; i++) {
      dontcare++;
   }
}

int main(int argc, char **argv)
{
   int mem_fd, i, j;
   int buf[4096];

   delay = atoi(argv[1]);

   if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC)) < 0) {
      perror("open /dev/mem");
      return -1;
   }

   if ((gpio = (volatile unsigned int *) mmap((caddr_t) 0x13370000, 4096, PROT_READ|PROT_WRITE,
                  MAP_SHARED|MAP_FIXED, mem_fd, GPIO_BASE)) == MAP_FAILED) {
      perror("mmap GPIO_BASE");
      return -1;
   }

   OUT_GPIO(N_WRITE_PROTECT);
   GPIO_SET_1(N_WRITE_PROTECT);

   OUT_GPIO(N_READ_ENABLE);
   GPIO_SET_1(N_READ_ENABLE);

   OUT_GPIO(N_WRITE_ENABLE);
   GPIO_SET_1(N_WRITE_ENABLE);

   OUT_GPIO(COMMAND_LATCH_ENABLE);
   GPIO_SET_0(COMMAND_LATCH_ENABLE);

   OUT_GPIO(ADDRESS_LATCH_ENABLE);
   GPIO_SET_0(ADDRESS_LATCH_ENABLE);

   OUT_GPIO(N_CHIP_ENABLE);
   GPIO_SET_0(N_CHIP_ENABLE);

   sleep(1);

   GPIO_SET_1(COMMAND_LATCH_ENABLE); shortpause();
   GPIO_SET_0(N_WRITE_ENABLE);
   set_data_direction_out(); GPIO_DATA8_OUT(0x90); // Read ID byte 1
   shortpause();
   GPIO_SET_1(N_WRITE_ENABLE);
   shortpause(); set_data_direction_in();
   GPIO_SET_0(COMMAND_LATCH_ENABLE);
   GPIO_SET_1(COMMAND_LATCH_ENABLE);
   shortpause();
   GPIO_SET_0(N_WRITE_ENABLE);
   set_data_direction_out(); GPIO_DATA8_OUT(0x00); // Read ID byte 2
   shortpause();
   GPIO_SET_1(N_WRITE_ENABLE);
   shortpause(); set_data_direction_in();
   GPIO_SET_0(ADDRESS_LATCH_ENABLE);
   shortpause();
   shortpause();
   shortpause();

   for (i = 0; i < 5; i++) {
      GPIO_SET_0(N_READ_ENABLE);
      shortpause();
      GPIO_SET_1(N_READ_ENABLE);
      buf[i] = GPIO_DATA8_IN();
      shortpause();
   }
   for (i = 0; i < 5; i++)
      printf("%02x", buf[i]);
   printf("\n");

   GPIO_SET_1(N_CHIP_ENABLE);

   return 0;
}
Attachments
IMG_0010a.JPG
IMG_0010a.JPG (56.75 KiB) Viewed 4866 times
Posts: 5
Joined: Thu Jul 12, 2012 10:05 pm
by pharos » Sat Sep 08, 2012 7:02 pm
It works! Just a small mistake, I inverted command latch and address latch in address cycle 1.

Code: Select all
root@raspberrypi:~# ./a.out 1
add8109544

Yes, that's a 5-byte NAND Flash ID above :)
Posts: 5
Joined: Thu Jul 12, 2012 10:05 pm
by pharos » Sun Sep 09, 2012 3:46 pm
So the NAND ID above is incorrect, it should be DA not D8. I've noticed the 360 Clip is extremely sensitive to the current position, which can be tiresome since the correct one must be maintained by applying pressure at the right spots when reading/writing the full NAND.

In any case, here's the most recent code:
rpi-tsop48-nand-v1.zip
(3.42 KiB) Downloaded 411 times
. I haven't added black erase/programming yet, but it should be straightforward. The code deals with the false contact problem issue by simply retrying the current page read in case of a problem, which allows moving the clip to eliminate the false contact.

By the way, why can't we post .c and .txt files in the forum, but zip is allowed? This seems somewhat absurd.
Posts: 5
Joined: Thu Jul 12, 2012 10:05 pm
by Sizco » Sun Apr 07, 2013 10:44 am
Hi,
the link to your setup is broken.
Can you upload the picture again oder anybody else, please?
I need information how to connect the clip pins to the gpio pins.

Thanks.
Posts: 4
Joined: Sun Apr 07, 2013 10:42 am
by Sizco » Wed Apr 10, 2013 8:06 pm
Does anybody have an idea how to connect the nand clip with the rpi?
When I try to connect 3,3v and GND to the clip und press the clip on the nand chip, the pri makes a reset. I think i have to take the power from the psu.
But i don't know whick pins of the clip have to connect to which pins on the rpi.
Posts: 4
Joined: Sun Apr 07, 2013 10:42 am
by fdufnews » Thu Apr 11, 2013 9:29 am
External load on 3,3V is limited to 30mA
Posts: 156
Joined: Fri Oct 07, 2011 5:37 pm
by Sizco » Thu Apr 11, 2013 10:06 am
Ok, then it's better to use the external psu.
My problem is that I don't know how to connect the clip.

This is the clip pinout:
Image

The GND, VCC and IO pins are not the problem.
Posts: 4
Joined: Sun Apr 07, 2013 10:42 am
by Xumpy » Tue Jun 04, 2013 9:26 pm
Ok, So far I have the following for the links to the 360clip:

FRB1 : GPIO 1
RE : GPIO 18
FCE1 : GPIO 22
CLE : GPIO 17
ALE : GPIO 4
WE : GPIO 21
WP : GPIO 0
I/00 : GPIO 23
I/01 : GPIO 24
I/02 : GPIO 25
I/03 : GPIO 8
I/04 : GPIO 7
I/05 : GPIO 10
I/06 : GPIO 9
I/07 : GPIO 11

But I keep getting all zero's. When I apply pressure I sometimes get all 03 or 02 or I even saw 01 at a time.

Is it possible that this is because the power for my nand comes from the rpi and not an external psu?

I'm testing it on an xbox360. But I would like to use it for broken USB sticks.

Thnx,

Regards

Xump
Posts: 14
Joined: Tue Jun 04, 2013 9:23 pm
by Sizco » Thu Jun 13, 2013 7:34 pm
Hi Xumpy,

is the script recognizing your NAND chip with your setup?
You can test this with the parameter "read_id".
Posts: 4
Joined: Sun Apr 07, 2013 10:42 am
by Xumpy » Mon Jun 17, 2013 1:20 pm
Hey Sizco

Nope, my nand is not detected. Nor my xbox nand nor my usb nand.
Maybe I've connected something wrong but I don't think so. Could also be that my 360clip is broken.

I should learn how to etch smd.

Could someone confirm me that my wiring that I posted above is correct?

Thnx

Regards

Xump
Posts: 14
Joined: Tue Jun 04, 2013 9:23 pm
by PHPower » Tue Aug 13, 2013 11:22 am
Hi !

I'm about to buy the 360 Clip to dump my PS3 NAND.
I saw that Xumpy told how to connect the Pi to Clip

FRB1 : GPIO 1
RE : GPIO 18
FCE1 : GPIO 22
CLE : GPIO 17
ALE : GPIO 4
WE : GPIO 21
WP : GPIO 0
I/00 : GPIO 23
I/01 : GPIO 24
I/02 : GPIO 25
I/03 : GPIO 8
I/04 : GPIO 7
I/05 : GPIO 10
I/06 : GPIO 9
I/07 : GPIO 11


But I didn't really understood how to give power to the NAND.

Thanks,
User avatar
Posts: 84
Joined: Tue Jan 01, 2013 7:48 pm
Location: PACA
by jbri » Wed Jan 22, 2014 1:21 am
I've connected my pi to the clip and I give power to the nand externally via the psu of the device but every time I try read_id, it returns identical hex values. I've also tried reading a chip from an old usb device, but I get the same issue. Maybe it's just my poor soldering :oops: (my 360 clip 'side-board' didn't come with the pin connectors soldered).

Help anyone? I followed the wiring guide Xumpy posted.
Attachments
rp_x360_solder_8.png
side-board
rp_x360_solder_8.png (57.32 KiB) Viewed 1437 times
Posts: 1
Joined: Wed Jan 22, 2014 12:51 am