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;
}