Página 1 de 3
Memória RAM externa no LPC2478

Enviado:
02 Abr 2009 21:07
por styg
E ai rapaziada, acho que alguns de voces ja mexeram com memória externa né?
Bom, comecei a mexer com uma sdram no lpc2478 (pra aquele meu projeto), e ja rolou o primeiro problema (que bom, se fosse facil nao tinha graça).
A começar pelo keil não simular o EMC, o que dificulta bastante.
Peguei um código exemplo do keil pra lpc2478 com sdram da samsung (por sorte quase-compativel com a micron que to usando), beleza, dei uma adaptada no código e botei p/ depurar na coragem mesmo.
Esse programa que peguei fazia o seguinte, zerava a memoria, escrevia e depois lia e conferia, tudo com ponteiro, simples, mas não funcionando 100%
A principio na da código aqui, pra não chatear, só quero tirar umas dúvidas quanto ao funcionamento do emc:
1) depois de configurar o emc de acordo com a memória, acabou?? digo, a memória externa fica mapeada (primeiro banco em 0xA0000000), então boto um ponteiro apontando pra ela e aí é só ler/escrever que o controlador se vira?
2) nesse código tá ativado o modo burst (8 bytes), então, eu não consigo ler uma word apenas (minha memória é de 16bits x 4MB) ??
3) se minha memória é de 16 bits, eu só posso escrever variaveis de 16bits? ou posso escrever de 8 ou 32bits e o controlador tb se vira.
4) como que eu carrego o mode register? no código tem algo assim:
dummy = *((volatile unsigned short *)(SDRAM_BASE_ADDR | (0x33 << 12)));
o que seria isso??
se me ajudarem com isso ja tá otimo pra começar!

Enviado:
04 Abr 2009 23:07
por MarcusPonce
O EMC foi pensado para atrapalhar o mínimo e acelerar o máximo. Mas também ser flexível, então precisa de algumas configurações.
Respondendo os itens:
1) depois de configurar o o EMC tem que configurar a SDRAM. Depois de configurá-la então realmente pode usar um ponteiro para ler/escrever. Veja mais no item 4).
2) Os bursts são entre o EMC e a SDRAM, controlados pelo EMC. Seu código que está acessando a SDRAM usando um ponteiro não precisa se preocupar com a existência deles para funcionar.
3) Você usa um ponteiro para 8 bits (char), 16bits (short) ou 32 bits (int), o EMC se vira.
4) O mode register dentro da SDRAM é acessado de uma forma especial dentro de uma sequência de eventos necessários para inicializar a SDRAM. Esta linha de código para ler para a variável dummy serve para ajustar o mode register, desde que esteja dentro de uma sequência correta de eventos.

Enviado:
06 Abr 2009 13:33
por styg
Marcus, beleza, ajudou bastante.
Mas o exemplo que peguei, nao sei ta dando uns pau estranho, parece coisa desse burst... imagina que to rodando passo-a-passo no debugger esse codigo, quando ele le o conteudo do ponteiro (16bits) que aponta pra sdram, tu sabe como o emc vai entregar esse valor?
digo, o codigo solicitou 2 bytes, o emc só acessa em bursts de 8bytes.. ele acessa e le 6bytes a mais nao necessarios, ou oq?

Enviado:
06 Abr 2009 19:12
por MarcusPonce
Oi, o EMC tem uns buffers (RAM) internamente que ele mesmo administra. Quando é feita a leitura da SDRAM para (por exemplo ) entregar os 2 bytes solicitados pelo código, outros bytes adicionais podem ser lidos para um destes buffers dentro do EMC. Assim o código recebe 2 bytes mas já teremos outros à espera em um buffer dentro do EMC mas que você não pode acessar de propósito... Se o código quiser ler mais bytes nos endereços seguintes, o EMC te entrega direto do buffer aqueles que ele já leu.

Enviado:
06 Abr 2009 21:42
por styg
Cara, tens algum documento que fale a respeito disso pra me indicar? quero dar uma lida melhor a respeito desse assunto.

Enviado:
06 Abr 2009 22:49
por MarcusPonce
Tem na NXP:
http://www.nxp.com/acrobat_download/use ... 0237_3.pdf
Esta é a versão de 15/jan/2009. Veja na página 68.
Se a sua SDRAM não está respondendo como deveria, eu começaria verificando se aquela linha
dummy = *((volatile unsigned short *)(SDRAM_BASE_ADDR | (0x33 << 12)));
está ok. O que interessa verificar é fim dela: (0x33 << 12). Pode ser que a memória que você escolheu necessite de outro número (portanto outra configuração). Também não deixe de ler no datasheet da memória que você está usando o que significa cada bit dele.

Enviado:
07 Abr 2009 14:45
por styg
na verdade eu uso o user manual como biblia pra ir programando, queria saber de algo mais profundo, que revele as entranhas do emc
tipo esse documento da arm, mas que nao sei se diz respeito exatamente ao lpc2478..
http://infocenter.arm.com/help/topic/co ... p0_trm.pdf
vi em outro forum que o modo de carregar o load register, após enviar a instrução 'load register', acontece fazendo uma leitura, o que é muito bizarro e é dificil achar quem saiba explicar como funciona isso por a+b.
o valor que deve ser carregado no mode reg, blz ta no dxit, mas esse shift de 12 ai que nao sei o porque... tb ja vi em outro forum indicarem diferentes shifts dependendo da memoria usada.
uma coisa importante:
as linhas de controle da sdram que ativas em nivel baixo (we, cs..) voce coloca res pull-up externo?? eu nao to usando nada disso ja que os pinos tao configurados no PINMODE habilitado o pull-up interno (mas não sei se na função d controlador isso continua valendo)
valeu cara

Enviado:
07 Abr 2009 17:05
por MarcusPonce
Ótimo estar usando o user manual como bíblia, eu também faço isso.
Existe um AN10771: "Using the LPC24xx EMC peripheral to drive SDRAM", é este que você está usando também ?
No User Manual está escrito que o EMC é "ARM PrimeCell™ MultiPort
Memory Controller". O documento do seu link não é "multiport". Naquele site com documentos da ARM que você citou existem três que podem ser: PL176, PL175 ou PL172. Os dois primeiros citam DDR (que o EMC da LPC2478 não usa), então deve ser o PL172 que só cita SDRAM. Resta comparar...
Para carregar o register dentro da SDRAM é feita uma leitura (no código em C) porque fizeram a SDRAM de forma que ela lê do bus de endereço (e não do bus de dados) a configuração, quando é aplicada nos pinos de controle dela uma combinação de níveis que não acontece em R/W normal.
Para que a SDRAM receba esta combinação específica nos pinos de controle é que informamos antes ao EMC (no EMCDynamicControl) que vamos fazer isso, daí ele coloca os níveis corretos para a SDRAM capturar a configuração do bus de endereço.
O motivo da SDRAM ler do bus de endereço e não do bus de dados é um mistério... talvez algum motivo de um passado distante...
Não sei se você já percebeu, desculpe se estou chovendo no molhado, mas questão da configuração ser (X << Y): se você usar uma SDRAM de outra a capacidade, outra largura ou outras características é possível que a configuração mude. Se ligar a mesma SDRAM em outro micro (ARM9, outros fabricantes, etc) também é possível que a configuração mude. E com a sua SDRAM no seu micro também existe mais de uma forma de operar com ela, de maneira que o (X << Y) poderia mudar.
Pull-ups: não dá para usar pull-ups com um valor que realmente faça diferença sem comprometer o consumo, pois os valores teriam que ser muito baixos. Acontece que a SDRAM funciona a dezenas de MHz, daí que cada transição de nível precisa de alguns mA por bit.
Sobre comportamento estranho que você vem citando: pelo motivo exposto acima é que é difícil ligar a SDRAM no ARM e rodar a toda velocidade que o ARM permite sem montar em PCB 4 camadas . Talvez seja interessante testar o seu hardware com um clock mais baixo para ver se o problema é este.

Enviado:
07 Abr 2009 22:41
por styg
Ótimo post cara, me esclareceu bastante!! A explicaçao do mode register mesmo, mato a pau.
Mas não entendo o pq do shift, já que o valor considerado esta entre A0-11.
Bom, a primeira coisa que vou fazer é rever as ligaçoes entre memoria-mcu e depois baixar a frequencia de operaçao..
Não sei se tu sabe, mas to fazendo isso dai funfar em protoboard..
Por falar em esquema, é assim que to ligando a memoria (MT48LC4M16A2):
http://www.4shared.com/file/97344159/72 ... quema.html
E entendi quanto aos resistores de pull-up, mas então uso ou não? (No \CS por exemplo que não é de alta freq).

Enviado:
09 Abr 2009 13:48
por MarcusPonce
Obrigado, mas acho que o assunto vai longe ainda...
Eu mesmo tenho duas dúvidas/suspeitas:
1) No shift (X << Y), ACHO que o Y é exatamente o número de bits do endereçamento das linhas, na sua memória são 12. Mas não achei isso por escrito. ACHO que assim o circuito do EMC fica mais simples.
2) Seu esquema do link parece ok para conectar a SDRAM no ARM, mas eu tenho uma dúvida, mesmo olhando no manual não esclareci: Os pinos BA0 e BA1 da SDRAM servem para uma função bem diferente do ponto de vista de temporização em relação aos A0...An, pois selecionam um dentre quatro bancos internos. Então do EMC estes dois sinais deveriam sair por pinos específicos e me parece que seria mais lógico que saíssem sempre pelos mesmos dois pinos mesmo que a capacidade da memória (linhas x colunas) se alterasse. Ou seja, me parece que seria mais simples o circuito do EMC se sempre ligássemos A14 em BA1 e A13 em BA0, independentemente de quantas linhas x quantas colunas. Digo isso pois não achei um exemplo de SDRAM como a sua (que possui apenas A0...A11) conectada no LPC24xx. Você ligou na sequência, mas TALVEZ o EMC espere que você pule o A12 (deixando ele sem conectar) e ligue A14 em BA1 e A13 em BA0.
Eu não usaria pull-ups. Mesmo o \CS que tem período mais longo no estado ativado ainda precisa ter os instantes de mudança de nível bem precisos, portanto o LPC24xx vai usar corrente de mA para colocar em nivel alto ou baixo.
Sobre o protoboard: vi as fotos da primeira placa no outro tópico. Realmente seria melhor testar abaixando o clock para o mínimo possível. E para ajudar você poderia soldar um cabo grosso entre os GNDs do ARM e os GNDs da SDRAM. Pode ser a "malha" de um cabo blindado normal (não serve um fininho de fone), pelo menos isso. Também seria muito bom soldar uns 0,1uF SMDs bem junto do ARM e outros bem junto do pinos de alimentação da SDRAM.
É sempre bom lembrar que o LPC24xx faz a SDRAM rodar no mesmo clock principal dele. Se for 72MHz no ARM é o que a SDRAM vai usar.

Enviado:
09 Abr 2009 15:59
por MarcusPonce
Novidades sobre o shift (X << Y) da configuração interna da SDRAM:
NÃO é "exatamente o número de bits de endereçamento das linhas"
A assunto é mais complexo, está difícil uma documentação que entre a fundo neste tópico, vamos ver se ainda conseguimos encontrar algumas boas.
Basicamente descobri o seguinte:
Para configurar o registrador, o "X" vai ter que ser entregue ao A0..An da SDRAM, mas isso só vai acontecer quando o EMC entregar a parte alta do endereço. O shift é para preencher a parte baixa do endereço com zeros.
O valor do "Y" é o tamanho da parte baixa do endereço.
Y = C + W + B
C = Quantidade de bits para colunas
W = quantos bits de endereço são eliminados pela largura do bus de dados. Ou seja, um bus de 16bits elimina 1 bit de endereço e um bus de 32bits elimina 2 bits de endereço
B = SE for modo "high performance" então é a quantidade de bits para selecionar os bancos. Se for modo "low power" então é 0.
Nos registradores EMCDynamicConfig0-3 temos que escolher qual o modo que a SDRAM vai operar. A SDRAM pode operar em "High Performance" ou "Low Power".
Então ficam algumas dúvidas:
1) Aonde ligamos os sinais BA0 e BA1 da sua memória que não tem A12 ?
2) Esta ligação depende de ser "high performance" ou "low power" ?
3) Para "high performance" Y = 8 + 1 + 2 = 11 mesmo ?
4) Para "low power" Y = 8 + 1 = 9 mesmo ?

Enviado:
09 Abr 2009 17:57
por Sergio38br

Enviado:
10 Abr 2009 13:35
por styg
bom, eu vou testar essa nova configuraçao. se necessario tambem alterar a ligaçao de BA0 e BA1, pra ver o que funciona.
vou ver se consigo mexer nisso durante a proxima semana, que agora to ocupado com outras coisas.

Enviado:
17 Abr 2009 23:24
por styg
consegui voltar a testar a bagaça, continua dando umas coisa estranha, sacao só:
o código de teste é esse:
wr_ptr = (unsigned int *)SDRAM_BASE_ADDR;
for ( i= 0; i < 20; i++ )
{
*wr_ptr++ = 0;
}
wr_ptr = (unsigned int *)SDRAM_BASE_ADDR;
for (i=0; i<20; i++)
{
*wr_ptr++ = 0x1359BCDF;
}
bem simples, aponto o ponteiro wr_ptr pro inicio da area mapeada pra memoria externa(0xa0000000), dai primeiro apago um pedaço e reescrevo nesse pedaço uns valores repetidos. nesse caso gravo 20 vezes o valor 0x1359BCDF. Depois eu aponto pro inicio novamente e vejo que realmente escreveu.
Dai o que acontece é o seguinte:
End: 0xA000 0000 Valor: 0x1359 BCDF
End: 0xA000 0004 Valor: 0x1359 BCDF
End: 0xA000 0008 Valor: 0x1359 1359
End: 0xA000 000C Valor: 0x1359 1359
End: 0xA000 0010 Valor: 0x1359 BCDF
End: 0xA000 0014 Valor: 0x1359 BCDF
End: 0xA000 0018 Valor: 0x1359 1359
End: 0xA000 001C Valor: 0x1359 1359
e assim por diante, é como se ele gravasse 4 posiçoes corretamente (de 16bits) e depois trava nos próximos 4.
isso eu to testando com o load mode register dessa forma:
mode = *((volatile unsigned int *) (0xa0000000 | (0x33 << 12)));
e baixei a frequencia de clock para 12MHz

Enviado:
19 Abr 2009 22:46
por guest2003
Styg,
Acho que se você mudasse seu teste para alguma coisa assim
wr_ptr = (unsigned int *)SDRAM_BASE_ADDR;
for (i=0; i<20; i++)
{
*wr_ptr++ = i;
}
ou mesmo i*0x10000000
Talvez desse pra entender melhor como ele esta escrevendo as coisas na memoria... pois com valores fixos não sabemos quem esta zuando quem...
[]'s