Перейти к содержанию
    

AlanDrakes

Участник
  • Постов

    205
  • Зарегистрирован

  • Посещение

Весь контент AlanDrakes


  1. Default Handler вызывается в том случае, когда произошло прерывание, не описаное в коде (имеющее вектор в таблице, но не получившее обработчика). Рекомендую добавить в код строки: void HardFault_Handler(void) { while(1) {} };
  2. Такое поведение я бы понял при наличии буферов FIFO на кристалле (в частности, для STM32F745 / F3xx / F030 такое поведение нормально. Данные загружаются в регистр данных, но попадают в FIFO буфер, в очередь передачи (размер - 32 бита), и фактически буфер передачи в этот момент становится пуст. Но в указаном Вами кристалле, FIFO не описан, значит его и быть не должно. Если есть логический анализатор - можете попробовать выводить отладку на пины. Сверьтесь с графиком 248 (параграф 25.3.9) по передачи данных со стороны ведомого контроллера. Естественно, внутренние сигналы придётся выводить во вне во время прерываний. И помните, что последние будут отставать от фактического события. Но можно сильно увеличить делитель частоты для SPI, чтобы минимизировать отставание.
  3. Как-то у меня с аналогичным дымом сгорел STM32F103. Просто очень неудачно упал силовой провод (+12V) на тестовую плату. Естественно, щёлк, вспышка, снесло крышу одному сдвиговому регистру, контроллер задымил. Самое странное при этом, что он продолжал работать. Естественно, минус несколько IO портов, но в консоль он продолжал слать отчёты о загрузке системы, видимости части переферии (вокруг него) и даже мог связаться с соседним контроллером по внешней шине. Ток потребления, конечно, ушёл куда-то за 100мА. Но через минуту и это перестало работать. Да, пробой по кремнию прямо внутри кристалла это очень печальная штука. :(
  4. +1 Бэкапы-то сделали? А вообще, какой же он стал страшный :( Шрифты - ладно, читаемы. Переносы в блоке профиля пользователя - позабавили (слово "Микроконтроллеры" слегка порвалось, но это так, менлочи на самом деле). Половина заголовков на русском, половина - на английском. Постоянно запрашивает какие-то разрешения для сайта. Зачем? Раньше такого не было и было нормально (лично мне). И, да. Здравствуй, гигантизм кнопок :(
  5. stm32f4 + Chan's FatFS

    Пилил я как-то свой тест скорости карточек. Не оптимальный до ужаса. Тем не менее, результат был таким: File created. Write test... [0000000030.080] File write done. Total bytes written: 5242880 bytes. Time: 27684 ms. Avg: ~189 kBps Read test... [0000000036.114] File read done. Total bytes read: 5242880 bytes. Time: 6033 ms. Avg: ~869 kBps Здесь кристалл работал на ~96МГц, возможно, меньше. SDIO тактировалось от PLL на 48МГц. Если тактирование SDIO было быстрее тактирования ядра - работать с картой памяти было невозможно. Были у меня ещё какие-то весёлые проблемы с записью больших блоков через FatFS, хотя библиотека собиралась с неправильными параметрами, и объём памяти под неё старательно ужимался. В итоге, при записи огромных буферов из памяти (как раз размером в несколько секторов) получал странные зависания в случайных местах. В причинах не разобрался, добавив костыль, заставив код писать мелкими блоками.
  6. stm32f4 + Chan's FatFS

    Помнится мне, что вся работа с секторами происходит в файле ff.c, а работа с низкоуровнемыми командами записи - в diskio.c, где уже Вы, по желанию, можете делать запись мультисекторно, или посекторно. При наличии больших буферов ФС - драйвер технически может вызывать функцию disk_write с параметром "Количество секторов", отличным от единицы. Фактически, единственный такой вызов я нашёл в функции f_write() в том случае, если ЕСТЬ свободные сектора, куда это поместится, и размер данных больше чем на один сектор. Так что, весь разбор что и куда писать, находится выше. Драйверу же карты передаются только команды "Пиши вот это, вот сюда, в таком-то количестве".
  7. stm32f4 + Chan's FatFS

    Гарантия есть. Она в самой команде CMD25, которая пишет сектора последовательно, не получая номеров в процессе выполнения. Для её окончания даже есть команда CMD12 - STOP_TRANSMISSION. Документ SD Phisical Layer Specification так же говорит: CMD25: [Address (PTP) data transfer command] Args: [31..0] - Data Address Continuously writes blocks of data until a STOP_TRANSMISSION follows. Block length is specified the same as WRITE_BLOCK command. Переводим. "Последовательно пишет блоки данных до получения команды STOP_TRANSMISSION. Длина блока определяется аналогично команде CMD24 - WRITE_BLOCK" Для карт высокой ёмкости длина блока ВСЕГДА равна 512 (размеру сектора). Для карт обычной ёмкости её можно задавать командой CMD16 - SET_BLOCK_LEN
  8. stm32l

    На всех платах STM32* установлен ST-Link V2, которым можно программировать и отлаживать ЛЮБЫЕ кристаллы STM32. Используйте выведеный на отладчике 6-ти пиновый разъём для подключения к другому контроллеру.
  9. Судя по рабочим диаграммам в мануалах, сигнал WAIT принимается контроллером в расчёт уже ПОСЛЕ начала обращения к микросхеме памяти. Считается, что микросхема ВСЕГДА готова к обращению после завершения предыдущей операции. По поводу же арбитража - лично я бы предложил использовать бит выбора чипа памяти в качестве сигнала арбитража шины. К сожалению, ведомый контроллер сможет узнать о том, что шина недоступна только косвенно, например, дополнительно перечитав этот самый сигнал. Никакого DMA в этом случае не будет и в помине. Обращение - только атомарное, с логикой контроля ошибки и отказа арбитража. Я бы предположил в этом случае использовать аппаратную логику типа триггера, указывающего, было ли обращение к микросхеме памяти от мастера во время обращения ведомого, или что-то похожее. Либо попробовал поискать двухканальную память, умеющую работать на два устройства паралельно.
  10. У Вас есть кристалл с уникальным ID, прошитым на производстве. Напишите что-то совместимое с CAN шиной, что будет использовать какой-нибудь специфический канал для настройки именно ведомых. Допустим, при запуске все кристаллы одновременно ломятся в шину с сообщением и посылают свой номер в какое-то поле. Происходит коллизия. Коллизия решается, выигравший забирает первый диапазон адресов. Повторить до окончания коллизий. Допустим, адреса 0x00 ~ 0xFF, каналы по 16 адресов (0x10) Посылка -> Коллизия -> Разрешение -> Выигравший забирает адреса 0x00 ~ 0x0F и замолкает. Посылка -> Коллизия -> Разрешение -> Второй выигравший забирает 0x10 ~ 0x1F и тоже замолкает. И так далее. UPD: Я тут подумал. Эту же процедуру можно проводить только в случае возникновения коллизии при ответе контроллера. То есть, сеть может организовываться полностью сама. Разве что мастер не будет знать кто где. Настройка можно хранить в выделеной странице (двух) Flash-памяти, либо на врешней EEPROM микросхеме, а перенастраиваться только при обнаружении ошибки. Я сейчас мыслю, абстрагировавшись от работы шины данных. Есть знатоки работы CAN протокола? Как можно реализовать подобное, используя стандартные методы? Хотя, в моём случае, при построении сети, работа ведётся исключительно между мастером и ведомыми. И он же выдаёт им сетевые адреса. Да, слизано с больших сетей с DHCP сервером. При этом работает по двухпроводной схеме (нет, не RS-485).
  11. SMI протокол

    Поддерживаю вариант с ногодрыгом. Интерфейс хоть и имеет близкого родича - SPI, но момент переключения данных - середина тактового импульса, плюс двунаправленность шины... в общем, когда экспериментировал - написал ногодрыг для AVR кристалла (что было под рукой) и он даже корректно заработал. Во всяком случае, отклики на команды приходили без ошибок. Удалось даже настроить подключеную физику в режим петли... и получить ругань от коммутатора, в который это всё было включено, и блокировку порта. На STM32 изначально имеется возможность подключения к интерфейсу, при наличии Ethernet модуля на борту.
  12. [zanuda mode ON] Были варианты двустороннего обмена данными с контроллером (при прошивке) с использованием шифрования и ключём на основе UID чипа. Фактически, прошивка даже клиенту попадает в шифрованом виде. Были варианты обновления прошивки по воздуху (по сети), так же, без использования прошивки в чистом виде. Аналогично, шифрованая по сети. В чём отличие именно этого загрузчика от других? [zanuda mode OFF] Точно так же, можно привязать саму прошивку к UID чипа. Таким образом, её можно сделать бесполезной для всех остальных пользователей. Дело только в сложности алгоритма и проверках.
  13. О, снова знакомая тема вылезла. Где-то ранее я уже с этми же бился и даже победил. И ровно та же ситуация. Ремаппинг памяти и ВСЕ проблемы сразу же ушли.
  14. На практике такое возможно. На STM я бы рекомендовал разделить память на две секции, или даже три. Первая - собтвенно, загрузчик, который должен уметь необходимые интерфейсы - SDIO/WiFi/(добавить_нужное). Вторая - приложение Третья - какие-то данные, которые лучше хранить на плате а не на внешней памяти. Естественно, загрузчик должен иметь возможность читать/писать карту, проверять версии прошивки основного приложения и (возможно) ведомого контроллера. Мегу, кстати, очень просто программировать через интерфейс ISP (SPI + Reset в качестве /CS). Где-то я подобное использовал у себя. Суть в том, что большой контроллер переводит ведомого в режим программирования, сверяет прошивку, если нужно - стирает и загружает новую. После чего отпускает сброс и позволяет тому работать уже самостоятельно. Удобно тем, что интерфейс SPI позволяет передавать и данные и сразу же прошивку (когда нужно). Можете посмотреть в документации на любой AVR* как происходит последовательное программирование. Ничего сложного там нет. А вот с загрузчиком - как раз будут сложности.
  15. Кстати, у меня в одном типе плат стоит контроллер (STM32F103). В цепи питания стоит обычный электролит на, кажется, 4700uF. Настроен PVD на уровень 2.9V (номинальное - около 3.2). Когда внешнее питание пропадает - контроллер ловит прерывание от PWD и быстро отправляет в консоль ругань, что его обесточили. Согласен, не Ваш вариант. Но в это же время можно отключить всю мощную нагрузку (хотя велик риск не успеть) и быстро доделать какие-то вещи, пока ёмкость не истощилась. Могу ещё предложить контролировать входное напряжение и при его пропадании - так же всё отключать, пока не разрядились ёмкости. Но две секунды на запись - это минимум сам контроллер + память... память - не более 25мА, судя по даташиту. Контроллер, если сбросить частоту - можно получить около 10-20мА. Берём наихудшие значения (20+25), накидываем разные утечки и всё, что нельзя обесточить (+50мА). Необходимо: 45+50 = 95мА суммарно на 2 секунды. При этом нельзя ронять напряжение ниже 2.7V для памяти. При начальном питании в 3.3 получаем разницу в (3.3 - 2.7) = 0.6V. Негусто. Теперь считаем заряд 2.7 * 0.095 * 4(с) (снова берём худший вариант и накидываем ещё резерв времени) = 1.026J Неслабо так. Минимум, который у меня получается, без использования преобразователей, просто на шине питания - 0.6F Это при токе почти в 100мА. После разряда от 3.3 до 2.7, в конденсаторе останется ещё ~1.8J. Если использовать дополнительный преобразователь: IN -> BoostCap -> Main_3.3, то можно вытянуть из него порядка 2.5J, а это около 8-10 секунд работы. Естественно, минимум потребителей и высокий КПД. Ёмкость на 3F можно просто оставить на питании и мониторить вход. Начальная энергия - 16J, Конечная - 11J (3.3 -> 2.7). А вот запуск с таким конденсатором будет довольно тяжёлым.
  16. Согласен, но хотя бы иметь буфер для тех данных, которые собираемся записывать. Как вариант подобной структуры: typedef struct { uint64_t StartAddress; uint8_t WriteStarted; uint8_t WriteDone; uint8_t WerifyOK; uint16_t DataSize; uint8_t DataArray[512]; } WriteBuffer; Про размеры сектора - согласен, но я имел в виду хранение сектора перед записью. Вроди бы, большинство чипов позволяет записывать иногда даже по байту в сектор (хотя и не все), подавляющее большинство - пол килобайта. Хотя, могу быть неправ. Очень большие микросхемы пока не трогал - не приходилось.
  17. После перезапуска проверять состояние регистров причины и отсылать сообщения / писать их в логи? Ну это как вариант. А вообще - хороший вариант - внутренняя же трассировка проблемного события. Это когда код вместо резкой перезагрузки сохраняет состояние системы и пишет в консоль (или файл, а лучше в два) сообщение о том что произошло, когда, почему и дампы, дампы, дампы...
  18. stm32 SPI

    Частота обмена ВСЕГДА зависит от частоты мастера. Ведомый кристалл только выставляет соответствующий уровень на пине MISO в момент(ы) смены тактового сигнала SCK. Необходимое условие - частота обмена не более четверти тактовой частоты ведомого чипа. Заметьте, тактовой частоты его периферии. Приведу пример: Мастер: 8МГц. Ведомый: 8МГц. SPI мастера тактируется от внутренней частоты с делителем /2. Результатирующая - 4МГц (внутренняя) и 2МГц (максимальная частота на пине SCK (здесь я имею в виду полную смену тактового сигнала 0-1-0)). SPI ведомого тактируется от внутренней шины с делителем /4. Результатирующая - 2МГц (вроди бы, совпадает с внешней), но максимальная внешняя - 1МГц (тот же полный импульс 0-1-0). Так что, мастер должен дёргать пином минимум в 2 раза медленнее. 500кБод - вполне достаточно 1МГц на шине. На шине ведомого. Ну и мастер должен с этой частотой данные читать.
  19. stm32 SPI

    Таки странно. У меня в проекте было настроено так: Мастер чинает данные по DMA с ведомого. SPI настроен на работу с DMA. Размер посылки фиксирован на 8 байт. Ведомый так же настраивает SPI на работу с DMA (F030), но в режиме Slave - Ведомый. Сразу же настраиваются все указатели и режим кольцевого буфера (те же 8 байт в DMAxx->CNTDR). После этого в принципе забываю про обращение к настройкам и или данным. Буфер заполняется новыми данными, если пин /CS поднят (1). Если передача активна (/CS = 0) - контроллер уходит в ожидание на несколько милисекунд (фактически, уходит в __WFI() до прерывания от DMA о окончании передачи). После этого - забрасывает новые данные, если таковые есть (банально копирует данные из актуального буфера в буфер передачи) и они будут отправлены в следующем цикле. Пауз нет. Прерывания по смене состояния пина - нет. Обращения к памяти - только от DMA контроллера. // STM32F040 - Slave int main(void) { RCC->APB2RSTR = 0x00075A40; // Reset almost all on APB2 RCC->APB2RSTR = 0; RCC->APB1RSTR = 0x10FE4932; // Reset all on APB1 RCC->APB1RSTR = 0; RCC->AHBENR = 0x00020001; // GPIOA Enable, DMA Enable GPIOA->PUPDR |= 0x00000100; // GPIOA[4] PullUp. RCC->APB2ENR = RCC_APB2ENR_SPI1EN; // SPI1 Enable GPIOA->MODER = 0x6555AA54; // GPIOA.MODER = [OAOO OOOO AAAA OOOI] GPIOA->AFR[0] = 0; // GPIOA[4-7].Alternate -> SPI1 SPI1->CR1 = 0; SPI1->CR2 = 0742; // 8 bit, DMA-TX enabled SPI1->CR1 = SPI_CR1_SPE; // Channel enabled, slave. SPI1->CR2 = 0742; // 8 bit, DMA-TX enabled DMA1_Channel3->CPAR = (uint32_t)&(SPI1->DR); DMA1_Channel3->CMAR = (uint32_t)&(ButtonsPressed[0]); DMA1_Channel3->CCR = (DMA_CCR_MINC | DMA_CCR_CIRC | DMA_CCR_DIR | DMA_CCR_TCIE); DMA1_Channel3->CNDTR = 8; DMA1_Channel3->CCR |= DMA_CCR_EN; NVIC_SetPriority(DMA1_Channel2_3_IRQn, 1); NVIC_EnableIRQ(DMA1_Channel2_3_IRQn); NVIC_SetPriority(SysTick_IRQn, 0x00); // Настраиваем SYSTick. Наивысший приоритет. NVIC_EnableIRQ(SysTick_IRQn); // Включаем прерывание SYSTick. NVIC_SetPriority(SPI1_IRQn, 0x01); // Приоритет SPI1 ниже чем SysTick NVIC_EnableIRQ(SPI1_IRQn); // Включаем. while(1) { __WFI(); }; }; void SPI1_IRQHandler(void) { if (SPI1->SR & SPI_SR_MODF) { SPI1->CR1 = SPI1->CR1; // Вы таки не поверите, но это очищает некоторые флаги ошибки }; while(SPI1->SR & 0x0600) { (void)(SPI1->DR); // Если есть данные - читаем их. Они нам не нужны :( }; }; void DMA1_Channel2_3_IRQHandler(void) { if (DMA1->ISR & DMA_ISR_TCIF3) { DMA1->IFCR = DMA_IFCR_CTEIF3; // Очищаем флаг DMA1_Channel3->CCR &= ~DMA_CCR_EN; // Отключаем канал DMA1_Channel3->CNDTR = 8; // Снова вводим 8 байт на отправку DMA1_Channel3->CCR |= DMA_CCR_EN; // Переводим канал в состояние готовности }; if (DMA1->ISR & DMA_ISR_GIF3) { DMA1->IFCR = DMA_IFCR_CGIF3; // Очищаем флаг }; }; upd: Кстати, я слегка ошибся. Мастер читает НЕ в режиме DMA. Он просто читает while (hdr < 2) { // Ищем заголовок сообщения (если был сбой синхронизации). Теоретически должен сразу ловить заголовок, а сбой может быть только при первой передаче (или неподлюченом ведомом). for (i=0;i<16;i++) { GPIOE->BSRR = GPIO_BSRR_BS_11; // Deselect Keyboadr on SPI4 GPIOE->BSRR = GPIO_BSRR_BR_11; // Select Keyboadr on SPI4 SPI4->CR1 &= ~SPI_CR1_SPE; // Disable SPI4 and deselect slave SPI4->CR1 |= SPI_CR1_SPE; // Enable SPI4 and select slave SPI4->DR = 0xFF; // dummy while (!(SPI4->SR & SPI_SR_RXNE)); // Delay until read/write operation v = SPI4->DR; if (v == 0xAA) { hdr = 1; break; }; }; SPI4->DR = 0xFF; // dummy while (!(SPI4->SR & SPI_SR_RXNE)); // Delay until read/write operation v = SPI4->DR; if (v == 0x55) { hdr++; } else { hdr = 0; }; }; // Считываем текущее состояние for (i=0;i<6;i++) { SPI4->DR = 0xFF; // dummy while (!(SPI4->SR & SPI_SR_RXNE)); // Delay until read/write operation v = SPI4->DR; DataBuff[i+2] = v; }; OffTop: Привык, что SPOILER сворачивает текст.
  20. Наверное, у меня странный вариант решения вопроса, но.... Если сделать свой буфер записи в BackUP домене? Выделяется блок памяти, скажем, чуть больше сектора. В него пишется будущий сектор, добавляется пара флагов типа "Запись пошла", "Запись прошла", "Проверка успешна", ну и адрес записи. Соответственно, перед записью - взводим первый флаг. Обязательно БАЙТ-флаг. После записи - сразу же взводим второй флаг. После этого ПРОВЕРЯЕМ записаные данные. Если успешно - обнуляем адрес и очищаем память. В случае потери питания и после перезапуска кристалла, нужно проверить: 1. Ненулевой адрес записываемого блока данных. 2. Соответствие флагов - "Начали писать", "Закончили писать", "Проверили". 3. Выполнить соответствующие действия - стереть сектор, повторить запись. Понимаю, это не решает вопрос отказоустойчивости самого Flash накопителя, но хотя бы снижает потерю данных во время работы. Ну и разбиение данных на блоки для удобства.
  21. Помнится, при отключеных битах отладочных возможностей, отладка как раз таки будет отваливаться с руганью отладчика, что Target has gone или нечто подобное. Уже не вспомню сообщения Keil'а, но там было предложение прекратить текущую сессию отладки, от которого было невозомжно отказаться (только OK). HAL'ом стараюсь не пользоваться. Больно уж высокоуровневые они функции наворотили, да ещё в индусском стиле. Частенько у меня их инициализация на 50-100 строк после выпиливания проверок и сведения изменений к одной строке, завершалась за 4-5 строк итогового кода. Соответственно, и работало быстрее и занимало меньше пространства в памяти. А для сборки проекта в RAM это не пустой звук. Эх, надо бы поискать свою отладочную плату с L152. Хотя, там питание я разводил из рук вон плохо (всё соединено в общую линию без всяких заморочек). По поводу битов отладки - глава 30 - Debug Support Пункт 30.16.1 - Поддержка отладки в режимах низкого потребления. To enter low-power mode, the instruction WFI or WFE must be executed. The MCU implements several low-power modes which can either deactivate the CPU clock or reduce the power of the CPU. The core does not allow FCLK or HCLK to be turned off during a debug session. As these are required for the debugger connection, during a debug, they must remain active. The MCU integrates special means to allow the user to debug software in low-power modes. Для входа в режим низкого потребления, должна быть выполнена инструкция WFI или WFE. В контроллере реализовано несколько маломощных режимов, которые либо отключают тактирования ядра ЦП, или снижают потребляемую мощность. Отладочное ядро не позволяет отключать тактирование FCLK или HCLK во время отладки. Так как они требуются для отладчика в процессе отладки, они должны быть сохранены. Микроконтроллер модержит специальные механихмы, позволяющие пользователю отлаживать код в режиме низкого потребления. Bit 2 DBG_STANDBY: Debug Standby mode 0: (FCLK=Off, HCLK=Off) The whole digital part is unpowered. From software point of view, exiting from Standby is identical than fetching reset vector (except a few status bit indicated that the MCU is resuming from Standby) 1: (FCLK=On, HCLK=On) In this case, the digital part is not unpowered and FCLK and HCLK are provided by the internal RC oscillator which remains active. In addition, the MCU generate a system reset during Standby mode so that exiting from Standby is identical than fetching from reset Бит 2. 0 - После инструкции WFI/WFE частоты FCLK, HCLK отключены. Для ПО выход из даннго состояния равносилен переходу на вектор сброса. 1 - В этом случае, цифровая часть НЕ обесточекна и частоты присутствуют и предоставляются внутренним RC-генератором, который остаётся активен. В дополнении, контроллер генерирует системный сброс во время состояния Standby, так что выход из режима ТАК ЖЕ происходит через точку сброса.
  22. 1. Выход из режима StandBy подразумевает ПОЛНЫЙ сброс ядра. Автоматически у Вас должна сброситься отладка. 2. Инструкция WFI без дополнительной настройки отправит ядро в режим сна (Sleep). При этом ядро будет запитано, как и память и вся периферия, а так же источники тактирования. 3. Эпизодически подключеный отладчик может вызывать прерывания типа DebugMon_Handler и что-то похожее. Не углублялся, тут могу ошибиться. Для перехода в режим именно StandBy необходимо: PWR->CR |= PWR_CR_PDDS; SCB->SCR |= SCB_SCR_SLEEPDEEP; PWR->CSR &= ~PWR_CSR_WUF; И сбросить соответствующие флаги RTC, чтобы контроллер не проснулся сразу же. После выполнения инструкции WFI отладка отвалится! Референс-мануал, глава 5.3.8 - StandBy Mode.
  23. web на stm32

    Паузы, судя по дампу, делает не компьютер, а контроллер отдаёт пакеты со скоростью 5 пакетов в секунду. Ищите, почему у Вас так редко происходит отправка пакетов. Возможно большие накладные расходы. Возможно редко вызывается поллер сети. Возможно ещё до чёртиков вариантов. Если есть свободные пины - выводите на них сигнал при отправке данных, например. Начало отправки - пин поднимается. Конец отправки - опускается. Наблюдайте за сигналом. Когда поднимается, что долго держит контекст исполнения. И так далее. Задержки - стабильны - 200мс. Значит, явно дело в коде. На том же кристалле (разве что без других задач) можно гнать трафик более 50МБит/с (проверял на UDP).
  24. Всё же, рекомендую аппаратную отладку прямо на кристалле. Идеально - если в схеме. А вообще - приведите код инициализации и подробно опишите, что именно не работает - скорее всего, найдётся причина.
  25. Обработчики функций библиотеки дописывали сами? Попробую привести пример своих, может поможет чем. Сразу поясню: сталкивался с какими-то весёлыми косяками при работе с несколькими картами (всеми имевшимися на тот момент в наличии), код привёл к тому виду, в котором он сейчас. На тот момент всё работало стабильно, читалось, писалось. Попробуйте, может и заработает. DRESULT disk_read ( uint8_t pdrv, /* Physical drive nmuber to identify the drive */ uint8_t *buff, /* Data buffer to store read data */ DWORD sector, /* Sector address in LBA */ UINT count /* Number of sectors to read */ ) { <...> //case MMC : //// translate the arguments here //result = MMC_disk_read(buff, sector, count); result = 0; if (count == 1) { result = SPI_SD_READ_SECTOR_buf(sector, m_buf); } else { while (count>0) { result = SPI_SD_READ_SECTOR_buf(sector, m_buf); count--; sector++; }; }; return result; <...> uint8_t SPI_SD_READ_SECTOR_buf(uint32_t Sector, uint8_t* buff) { uint16_t i; uint32_t calc_Addr; SPI_Select_CARD(); if (!(sd_raw_card_type & (1 << SD_RAW_SPEC_SDHC))) // Если карта НЕ является SDHC - добавляем 9 бит к адресу. { // !SDHC calc_Addr = ((Sector+249) << 9); // DaFaq?! But will not work in other case. } else { // SDHC calc_Addr = (Sector+2048); // And one more DAFAQ! }; i = SPI_SD_SendCMD(CMD_READ_SINGLE_BLOCK, calc_Addr); // Передаём вычисленный адрес карте card_answ_at_read = i; // DEBUUUUUG! if(i) { SPI_UnSelect_CARD(); // Отпускаем карту return R_ERR; // Возвращаем ошибку. =( }; while (SPI_Rd_Byte() != 0xFE); // Ждём начала блока. Чаще всего до 30-40 итераций. for (i=0; i<512; i++) // Читаем байт и заносим его в буфер (512 байт) { *buff = SPI_Rd_Byte(); buff++; }; SPI_Rd_Byte(); // CRC SPI_Rd_Byte(); // CRC (2) // IGNORED T_T /* deaddress card */ SPI_UnSelect_CARD(); // Отпускаем карту (шину) SPI_Rd_Byte(); // Тактирование. return R_OK; }; ЗЫ: Обратите внимание на комментарии около странных переводов значений секторов. Особенно, +249
×
×
  • Создать...