TAutomatic 0 26 мая, 2012 Опубликовано 26 мая, 2012 · Жалоба Добрый день, коллеги. Волею судьбы пришлось использовать ARM в разработке. Столкнулись с такой проблемой. Нужно связать LPC1768 и AT45DB321. Опыт работы с этой датафлеш есть предостаточный, но все на PIC. Так вот, в чем проблема. Если использовать модуль SPI, вопросов не возникает, рабочий код для PIC был портирован практически без изменений и работает. Все бы ничего, но скорость обмена не более 12МГц. Датафлеш позволяет обмениваться быстрее, что собственно и нужно. При использовании SSP возникают нюансы, а именно: включается буфер FIFO глубиной 8 слов. Пока он не заполнен до верху, получается, невозможно считать данные. Допустим, кто знаком с работой датафлеши, на запрос о статусе надо принять всего единственный байт. Невозможно его получить, пока 8 раз не запросишь. Это разве удобства? А если выполнить блочное чтение, значит, нужно читать на 8 байт больше, что бы считать на вершине буфера свой нужный последний? Или я чего-то не понимаю? Почему у модуля УАРТ можно указать глубину буфера Фифо, тут нельзя. Как дали, так и кушать? Может кто подскажет, как проще выкрутиться? Заранее спасибо. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 242 26 мая, 2012 Опубликовано 26 мая, 2012 · Жалоба Не очень понятно в чём проблема? Работаю именно с этой AT45DB321 и с LPC1788 и ранее - с LPC2378 через SSP без проблем. Как с DMA, так и без. На SCLK==30МГц. Статус - читается только один байт. enum {CDF_STATUS = 0xD7}; //чтение регистра статуса //Возвращает статус static u32 WaitRDY(int hold = 0) { u32 i, j; volatile HwRegsSSP *ssp = &concatAB(SSP, nSSP_dflash); ssp->CR[0] = 15 | B6 | B7; ssp->CR[1] = B1; while (1) { ssp->DR = CDF_STATUS << 8; while (ssp->SR & B4); if ((i = ssp->DR) & B7) break; if (!hold) PostDF(); OSTimeDly(ms2tkt(2)); if (!hold) PendDF(); } ssp->CR[1] = 0; j = i & 0x3D; if (j != 0x2C && j != 0x34) trap(TRAP_DFLASH); return i; } void InitSSP(SspCtl *p, volatile HwRegsSSP *ssp, u32 cpsr) { ssp->IMSC = ssp->CR[1] = 0; ssp->CPSR = cpsr; ssp->DMACR = 0; while (ssp->SR & B2) { u32 i = ssp->DR; } p->mbox = MboxCreate(); SemPend(p->sem = SemCreate()); //блокируем до выполнения функции, конфигурирующей устройство } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
TAutomatic 0 26 мая, 2012 Опубликовано 26 мая, 2012 · Жалоба Ну мне кажется, я достаточно подробно описал, в ЧЕМ проблема. Но все равно спасибо, за ответ. Впрочем, я не проверял работоспособность Вашего кода. Там есть кое-какие отсутствующие куски, что бы просто скопировать и попробовать у себя. Но на взгляд, у меня вызывает вопрос строчка кода if ((i = ssp->DR) & B7) break; Мне все абсолютно ясно в ней, поскольку используем, как я уже сказал, AT45DB321 в проектах на PIC16, PIC18, PIC24 без всяких трудностей. Но у меня она не дает сразу нужного результата, пока я не выполню чтение 8 раз, тоесть пока самый первый байт не окажется на вершине буфера FIFO. Как у Вас так просто получается, надо разобраться. Кстати, при использовании DMA допускаю, что работает как раз все предсказуемо, поскольку модули DMA не используют буферы FIFO периферии, а читают сразу из входных регтсров. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aaarrr 69 26 мая, 2012 Опубликовано 26 мая, 2012 · Жалоба Допустим, кто знаком с работой датафлеши, на запрос о статусе надо принять всего единственный байт. Невозможно его получить, пока 8 раз не запросишь. Это не так. Никто не заставляет заполнять FIFO полностью, можно и один байт получить-считать. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
TAutomatic 0 26 мая, 2012 Опубликовано 26 мая, 2012 · Жалоба Это не так. Никто не заставляет заполнять FIFO полностью, можно и один байт получить-считать. Каким образом? Это и есть то, о чем я спрашиваю. Я кидаю команду чтения статуса. Вижу в SSP->DR принятый байт 0xFF, все правильно. Теперь кидаю байт 0xFF для тактирования ответного байта( в отличии от коллеги, я использую не 16 битовый формат, а 8 битовый), в ответ в SSP->DR я вижу отладчиком нужное значение статуса, но считвается оттуда 0. И так еще семь раз подряд. И только 8 вытолкнет нужное мне значение наружу, и я могу его считать. Так что именно неправильно? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aaarrr 69 26 мая, 2012 Опубликовано 26 мая, 2012 · Жалоба ..вижу отладчиком нужное значение статуса, но считвается оттуда 0. Потому что отладчик уже считал этот статус. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
TAutomatic 0 26 мая, 2012 Опубликовано 26 мая, 2012 · Жалоба У коллеги, кстати, тоже не так работает, как хотелось бы, а так как получается и у меня. Единственное, что спасает - тот кусок кода - "вечный" цикл. Через определенное количество чтений буфер таки заполняетя, как и ожидалось, и цикл вываливается наружу с "нужным" результатом. Потому что отладчик уже считал этот статус. Имеет смысл убрать отладчик и проверить без его вмешательства? Ну может быть. Надо поробовать Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 242 26 мая, 2012 Опубликовано 26 мая, 2012 · Жалоба У коллеги, кстати, тоже не так работает, как хотелось бы, а так как получается и у меня. Единственное, что спасает - тот кусок кода - "вечный" цикл. Через определенное количество чтений буфер таки заполняетя, как и ожидалось, и цикл вываливается наружу с "нужным" результатом. Это как у меня "не так" работает?? То что я вам привёл - это выдрано из рабочего ПО, которое вполне нормально работает. Часть - с DMA, часть - без. 16-битное - для оптимизации и для того, чтобы не запрещать прерывания на время нескольких операций записи в ssp->DR (у меня сигнал CS формируется аппаратно SSP). Цикл там только для случая, если флешка занята предыдущей операцией, если нет - проходит его в один проход. FIFO - это не причина для того чтобы не давать доступа к одному байту, оно нисколько не мешает. Это у вас там каша какая-то. aaarrr вам правильно написал - не надо лезть отладчиком в работающие регистры SSP. Чтение JTAG - то же самое, что чтение CPU. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
TAutomatic 0 26 мая, 2012 Опубликовано 26 мая, 2012 · Жалоба Это как у меня "не так" работает?? То что я вам привёл - это выдрано из рабочего ПО, которое вполне нормально работает. Часть - с DMA, часть - без. 16-битное - для оптимизации и для того, чтобы не запрещать прерывания на время нескольких операций записи в ssp->DR (у меня сигнал CS формируется аппаратно SSP). Цикл там только для случая, если флешка занята предыдущей операцией, если нет - проходит его в один проход. FIFO - это не причина для того чтобы не давать доступа к одному байту, оно нисколько не мешает. Это у вас там каша какая-то. aaarrr вам правильно написал - не надо лезть отладчиком в работающие регистры SSP. Чтение JTAG - то же самое, что чтение CPU. Коллега не кипятитесь по-напрасну. И не выдергивайте куски из текста. Я написал, что не работает, так как хотелось бы. В том то и дело, что Ваш пример - выдранный кусок. Вместе с семафорами и тому прочее, который я немогу опробовать в полном объеме. Я удалил все лишнее, и пишу, что вижу: под отладчиком Ваш код работает, также как и мой. И всего лишь. Не надо лишних обид. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
DmitryM 0 27 мая, 2012 Опубликовано 27 мая, 2012 · Жалоба Допустим, кто знаком с работой датафлеши, на запрос о статусе надо принять всего единственный байт. Невозможно его получить, пока 8 раз не запросишь. А какже следующее замечание для AT45DB321? "After the one byte of the status register has been clocked out, the sequence will repeat itself (as long as CS remains low and SCK is being toggled). The data in the status register is constantly updated, so each repeating sequence will output new data." Читайте себе на здоровье пока фифо не заполнится без перезапросов. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Артём__ 0 27 мая, 2012 Опубликовано 27 мая, 2012 · Жалоба А какже следующее замечание для AT45DB321? "After the one byte of the status register has been clocked out, the sequence will repeat itself (as long as CS remains low and SCK is being toggled). The data in the status register is constantly updated, so each repeating sequence will output new data." Читайте себе на здоровье пока фифо не заполнится без перезапросов. Смысл читать статус если, например запущена запись страницы длительностью несколько десятков мс? Можно заняться чем нибудь более полезным. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
DmitryM 0 27 мая, 2012 Опубликовано 27 мая, 2012 · Жалоба Смысл читать статус если, например запущена запись страницы длительностью несколько десятков мс? Можно заняться чем нибудь более полезным. Дык один раз подождал пока фифо не заполнилось и ушел заниматься полезным, если условие не удовлетворило, потом еще раз прочитал. Наверняка там еще и прерывание по заполнению фифо можно задействовать, если уж так пендитно ко времени простоя. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
TAutomatic 0 27 мая, 2012 Опубликовано 27 мая, 2012 · Жалоба А какже следующее замечание для AT45DB321? "After the one byte of the status register has been clocked out, the sequence will repeat itself (as long as CS remains low and SCK is being toggled). The data in the status register is constantly updated, so each repeating sequence will output new data." Читайте себе на здоровье пока фифо не заполнится без перезапросов. Это замечание справедливо, и я им пользуюсь. После выдачи команды я в цикле посылаю только байт синхронизации 0xFF уже без команды, в отличии от коллеги, который привел кусок кода. Спасибо ему. Ну так и у меня заполняется буфер фифо, и рано или поздно я получаю искомый байт статуса. Считаете, это нормально? Вот таким образом неэффективно строить обмен? Вместо одного байта посылать 8 для получения результата? Это не мой метод. Должно быть красивое решение. Наверняка оно есть. Я знаток пиков, там все работает гуд, программируется и настраивается легко. Наверно и в ARM тоже все нормально, простоя пока мало знаком с ним. Дык один раз подождал пока фифо не заполнилось и ушел заниматься полезным, если условие не удовлетворило, потом еще раз прочитал. Наверняка там еще и прерывание по заполнению фифо можно задействовать, если уж так пендитно ко времени простоя. Не все так просто. Если бы можно было бы изначально заполнить и не париться- вопросов не возникло бы. Дело в том, что отправка команд и данных в сторону датафлеши вызывает прием в буфер данных типа 0xFF. Поэтому перед каждой операцией получения данных надо заново перезаполнять буфер. Или читать на 8 байт больше, чем нужно. Это хорошо с чтением данных или статуса, который можно прочитать в цикле несколько раз подряд и им заполнить буфер. А что делать с другими командами? несколько раз подряд их запрашивать? Нет, это неэффективно. Коллега прав, если у него работает, значит работает вообще, и у меня будет работать. Вот только где ошибка? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
aaarrr 69 27 мая, 2012 Опубликовано 27 мая, 2012 · Жалоба 1. Нет ни малейшей необходимости заполнять FIFO полностью. При запросе статуса просто пишем два байта, затем два байта читаем. Во втором находим искомый статус. Все. 2. Отладчик не должен ни в коем случае лезть в регистр данных SSP. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Артём__ 0 27 мая, 2012 Опубликовано 27 мая, 2012 · Жалоба 1. Нет ни малейшей необходимости заполнять FIFO полностью. При запросе статуса просто пишем два байта, затем два байта читаем. Во втором находим искомый статус. Все. Точно. Читал AT45 (правда на lpc11. но у них очень похожий SSP, может вам подойдёт): void InitLpcSSP0_IO() { // сброс SSP0 LPC_SYSCON->PRESETCTRL |= (1<<0); // тактирование SSP0 LPC_SYSCON->SYSAHBCLKCTRL |= (1<<11); // делитель на 2 LPC_SYSCON->SSP0CLKDIV = 0x02; /* SSP I/O config */ /* SSP MISO */ LPC_IOCON->PIO0_8 &= ~0x07; LPC_IOCON->PIO0_8 |= 0x01; /* SSP MOSI */ LPC_IOCON->PIO0_9 &= ~0x07; LPC_IOCON->PIO0_9 |= 0x01; // SCK на вывод 2.11 LPC_IOCON->SCK_LOC = 1; LPC_IOCON->PIO2_11 = 0x01; // Enable AHB clock to the GPIO domain. LPC_SYSCON->SYSAHBCLKCTRL |= (1<<6); // SSP SSEL is a GPIO pin LPC_IOCON->PIO0_2 &= ~0x07; // port0, bit 2 is set to GPIO output and high LPC_GPIO0->DIR|=1<<2; LPC_GPIO0->DATA|=1<<2; } void InitSSP0() { // Set DSS data to 8-bit, // Frame format SPI, //CPOL = 0, CPHA = 0, and SCR is 15 LPC_SSP0->CR0 = 0x0707; // SSPCPSR clock prescale register, //master mode, minimum divisor is 0x02 LPC_SSP0->CPSR = 0x2; for ( unsigned char i = 0; i < FIFOSIZE; i++ ) { unsigned char Dummy = LPC_SSP0->DR; /* clear the RxFIFO */ } /* Enable the SSP Interrupt */ //NVIC_EnableIRQ(SSP0_IRQn); /* Device select as master, SSP Enabled */ /* Master mode */ LPC_SSP0->CR1 = (1<<1); /* Set SSPINMS registers to enable interrupts */ /* enable all error related interrupts */ // SSPIMSC_RORIM | SSPIMSC_RTIM; LPC_SSP0->IMSC = (1<<0)|(1<<1); } void SSP0_SendData(uint8_t *buf, uint16_t Length ) { uint32_t i; uint8_t Dummy = Dummy; for ( i = 0; i < Length; i++ ) { /* Move on only if NOT busy and TX FIFO not full. */ while ( (LPC_SSP0->SR & (SSPSR_TNF|SSPSR_BSY)) != SSPSR_TNF ); LPC_SSP0->DR = *buf; buf++; while ( (LPC_SSP0->SR & (SSPSR_BSY|SSPSR_RNE)) != SSPSR_RNE ); //Whenever a byte is written, MISO FIFO counter increments, Clear FIFO //on MISO. Otherwise, when SSP0Receive() is called, previous data byte //is left in the FIFO. Dummy = LPC_SSP0->DR; } } void SSP0_Receive(uint8_t *buf, uint16_t Length) { uint32_t i; for ( i = 0; i < Length; i++ ) { //As long as Receive FIFO is not empty, I can always receive. // If it's a loopback test, clock is shared for both TX and RX, // no need to write dummy byte to get clock to get the data // if it's a peer-to-peer communication, SSPDR needs to be written //before a read can take place. LPC_SSP0->DR = 0xFF; /* Wait until the Busy bit is cleared */ while ( (LPC_SSP0->SR & (SSPSR_BSY|SSPSR_RNE)) != SSPSR_RNE ); *buf = LPC_SSP0->DR; buf++; } } unsigned char AT45_GetStatus() { SSP0_CS_Clr(); uint8_t cmd_code=0xD7; SSP0_SendData(&cmd_code, 1); uint8_t status; SSP0_Receive(&status, 1); SSP0_CS_Set(); return status; } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться