#include "at32f403a_407.h" #include "spi_flash.h" #include "spi_common.h" #include "FreeRTOS.h" #include "task.h" #include "common_config.h" #include #include #define SPI_FLASH SPI3 #define INCLUDE_SPI_TEST 0 //SemaphoreHandle_t spi_mutex; static uint8_t spi_tx_rx(uint8_t byte) { return common_spi_tx_rx(SPI_FLASH, byte); } #define CMD_WREN 0x06 // + #define CMD_WRDI 0x04 // + #define CMD_WRSR 0x01 // + #define CMD_RDSR 0x05 // + #if defined (FLASH_TYPE_AT25SF161) #define CMD_READ 0x03 //0x0B // + #elif defined (FLASH_TYPE_MX25L1606E) #define CMD_READ 0x03 // + #endif #define CMD_SE 0x20 // + Block Erse 4 Kbytes #define CMD_BE 0x52 // Block Erase 32 Kbytes #define CMD_CE 0x60 // + Chip Erase #define CMD_PP 0x02 // + Byte/Page Program (1 to 256 Bytes) #define CMD_RDSFDP 0x5A // - not used for FLASH_TYPE_AT25SF161 #define SR_WIP (1 << 0) #define SR_WEL (1 << 1) #define SR_SRWD (1 << 7) static spi_flash_desc_t spi_flash_desc; static inline void wait_write_enable(void) { uint8_t status; SPI_FLASH_CS_L(); spi_tx_rx(CMD_RDSR); do { status = spi_tx_rx(0); } while (!(status & SR_WEL)); SPI_FLASH_CS_H(); } static inline void wait_write_end(void) { uint8_t status; SPI_FLASH_CS_L(); spi_tx_rx(CMD_RDSR); do { status = spi_tx_rx(0); } while (status & SR_WIP); SPI_FLASH_CS_H(); } static inline void send_addr(int addr) { spi_tx_rx((addr >> 16) & 0xFF); spi_tx_rx((addr >> 8) & 0xFF); spi_tx_rx(addr & 0xFF); } static int spi_flash_read_sfdp(int addr, void *buf, size_t len) { uint8_t *ptr = (uint8_t*)buf; //xSemaphoreTake(spi_mutex, portMAX_DELAY); SPI_FLASH_CS_L(); spi_tx_rx(CMD_RDSFDP); send_addr(addr); spi_tx_rx(0); while (len--) *ptr++ = spi_tx_rx(0); SPI_FLASH_CS_H(); //xSemaphoreGive(spi_mutex); return 0; } ssize_t spi_flash_read(int addr, void *buf, size_t len, uint32_t timeout) { uint8_t *ptr = (uint8_t*)buf; (void)timeout; //xSemaphoreTake(spi_mutex, portMAX_DELAY); SPI_FLASH_CS_L(); spi_tx_rx(CMD_READ); send_addr(addr); while (len--) *ptr++ = spi_tx_rx(0); SPI_FLASH_CS_H(); //xSemaphoreGive(spi_mutex); return len; } #define TIMEOUT 10000 uint16_t spi_flash_pp(int addr, const void *buf, size_t len, uint32_t timeout) { uint8_t *ptr = (uint8_t*)buf; (void)timeout; ssize_t ret = 0; if ((addr & 0xFF) + len > 0xFF) len = 0x100 - (addr & 0xFF); ret = len; //xSemaphoreTake(spi_mutex, portMAX_DELAY); SPI_FLASH_CS_L(); spi_tx_rx(CMD_WREN); SPI_FLASH_CS_H(); wait_write_enable(); SPI_FLASH_CS_L(); spi_tx_rx(CMD_PP); send_addr(addr); while (len--) spi_tx_rx(*ptr++); SPI_FLASH_CS_H(); wait_write_end(); //xSemaphoreGive(spi_mutex); return ret; } ssize_t spi_flash_write(int addr, const void *buf, size_t len, uint32_t timeout) { (void)timeout; int ret = 0, offset = 0; do { ret = spi_flash_pp(addr + offset, (uint8_t*)buf + offset, len - offset, 0); offset += ret; } while (len - offset); return 0; } int spi_flash_chip_erase(uint32_t timeout) { (void)timeout; //xSemaphoreTake(spi_mutex, portMAX_DELAY); SPI_FLASH_CS_L(); spi_tx_rx(CMD_WREN); SPI_FLASH_CS_H(); wait_write_enable(); SPI_FLASH_CS_L(); spi_tx_rx(CMD_CE); SPI_FLASH_CS_H(); wait_write_end(); //xSemaphoreGive(spi_mutex); return 0; } int spi_flash_erase_sector(int addr, uint32_t timeout) { (void)timeout; //xSemaphoreTake(spi_mutex, portMAX_DELAY); SPI_FLASH_CS_L(); spi_tx_rx(CMD_WREN); SPI_FLASH_CS_H(); wait_write_enable(); SPI_FLASH_CS_L(); spi_tx_rx(CMD_SE); send_addr(addr); SPI_FLASH_CS_H(); wait_write_end(); //xSemaphoreGive(spi_mutex); return 0; } unsigned int spi_flash_get_sector_size(void) { return spi_flash_desc.sector_size; } unsigned int spi_flash_get_sector_count(void) { return spi_flash_desc.sector_count; } unsigned int spi_flash_get_total_size(void) { return spi_flash_desc.sector_count * spi_flash_desc.sector_size; } bool spi_flash_is_init(void) { return spi_flash_desc.present; } bool spi_flash_init(void) { bool ret = false; uint8_t tmp[4] = {0}; SPI_FLASH_CS_H(); spi_flash_get_id(tmp); if (!(tmp[0] == 0x1F && tmp[1] == 0x86 && tmp[2] == 0x01)) { ret = false; spi_flash_read_sfdp(0, tmp, 4); if (!(tmp[0] == 0x53 && tmp[1] == 0x46 && tmp[2] == 0x44 && tmp[3] == 0x50)) ret = false; else ret = true; } else ret = true; if (ret) { spi_flash_desc.sector_size = SPI_FLASH_SECTOR_SIZE; spi_flash_desc.sector_erase_op = 32; spi_flash_desc.sector_count = 512; spi_flash_desc.present = true; return true; } else return false; #if 0 #if defined (FLASH_TYPE_AT25SF161) uint8_t tmp[4] = {0}; SPI_FLASH_CS_H(); spi_flash_get_id(tmp); if (!(tmp[0] == 0x1F && tmp[1] == 0x86 && tmp[2] == 0x01)) return 0; spi_flash_desc.sector_size = SPI_FLASH_SECTOR_SIZE; spi_flash_desc.sector_erase_op = 32; spi_flash_desc.sector_count = 512; spi_flash_desc.present = true; return 1; #elif defined (FLASH_TYPE_MX25L1606E) uint32_t i, ptable, bitsize = 0; uint8_t tmp[4]; spi_flash_desc.present = false; // check SFDP magic SPI_FLASH_CS_H(); spi_flash_read_sfdp(0, tmp, 4); if (!(tmp[0] == 0x53 && tmp[1] == 0x46 && tmp[2] == 0x44 && tmp[3] == 0x50)) return 0; // get parameter headers count spi_flash_read_sfdp(0x06, tmp, 1); // find first jedec pheader (with ID == 0) for (ptable = 0x08, i = 0; i <= tmp[0]; i++, ptable += 8) { spi_flash_read_sfdp(ptable, tmp, 1); if (tmp[0] == 0) break; } // read ptable pointer from pheader spi_flash_read_sfdp(ptable + 4, &ptable, 3); // get flash density (size in bits) if (spi_flash_read_sfdp(ptable + 4, &bitsize, 4) < 0 || !bitsize) return 0; // find smallest available sector for (i = 0; i < 4; i++) { tmp[0] = 0; if (spi_flash_read_sfdp(ptable + 0x1C + i*2, &tmp, 2) >= 0 && tmp[0]) { spi_flash_desc.sector_size = 1 << tmp[0]; spi_flash_desc.sector_erase_op = tmp[1]; spi_flash_desc.sector_count = (bitsize + 1) >> (3 + tmp[0]); break; } } if (!spi_flash_desc.sector_size) return 0; spi_flash_desc.present = true; return 1; #endif return 0; #endif } /* bool spi_flash_init(void){ //spi_init_(); spi_flash_desc.sector_size = SPI_FLASH_SECTOR_SIZE; spi_flash_desc.sector_erase_op = 32; spi_flash_desc.sector_count = 512; spi_flash_desc.present = true; return 1; } */ /* void init_spi_mutex(void) { spi_mutex = xSemaphoreCreateMutex(); } */ // -------------------------------------------------------------------------- // void spi_flash_get_id(uint8_t *buf) { //xSemaphoreTake(spi_mutex, portMAX_DELAY); SPI_FLASH_CS_L(); spi_tx_rx(0x9F); *buf++ = spi_tx_rx(0); *buf++ = spi_tx_rx(0); *buf++ = spi_tx_rx(0); SPI_FLASH_CS_H(); //xSemaphoreGive(spi_mutex); } // -------------------------------------------------------------------------- // #if INCLUDE_SPI_TEST const uint8_t txbuf1[] = "This film came out on DVD yesterday and I rushed to buy it. \ This version is the first to render all the detail and perfection \ of Jack Cardiff's amazing compositions and brilliant, varied photography. \ As a collection of memorable images, this film is better than any comparable \ historical epic of the period and even gives GWTW a run for its money. \ King Vidor's direction is a series of 'tableaux vivants' where the \ characters are not posing but acting in a very natural, period-specific way. \ I have never had a problem with this adaptation of Tolstoy's novel. \ I think it is a wonderful introduction to the period and the novel and that \ it is a very poetic, very original work in its own right. Henry Fonda's \ characterization is especially moving, including great memorable interactions \ with/reations to Mel Ferrer, Audrey Hepburn, Helmut Dantine and John Mills, but \ all members of the cast are actually perfect. The harrowing last 45 minutes of \ the film manage to convey a sense of history, a sense of grandeur as well as to \ communicate very clearly Tolstoy's ideas about the meaning of life, by relying \ mostly on the power of memorable images. The most conspicuous handicap of this movie, \ in my opinion, is its soundtrack (in glorious mono). The barely hi-fi recording of \ dialogues and music sounds pinched, hollow and tinny and it always has in very version \ I have ever seen: in the theatres, on TV and on video. Even the soundtrack album is \ an atrocity. In some scenes, before the necessary adjustments of bass and treble, \ Audrey Hepburn's and Mel Ferrer's voices actually hurt your ear. Nino Rota's very \ Russian-sounding score is serviceable and melodic, although rather sparse in its \ orchestration and in the number of players. One can only wonder what 'War and Peace' \ could have sounded like with a cohort of Hollywood arrangers, decent recording facilities \ and lavish, varied orchestrations in true high fidelity and stereophonic sound. \ According to Lukas Kendall of 'Film Score Monthly', the original recording elements \ of the soundtrack have long ago disappeared, which is the common lot of international, \ independent co-productions of the era. Someone somewhere is certainly guilty of \ skimping on quality or embezzlement for this 1956 movie to sound so much worse \ than a 1939, pre-hi-fi epic like GWTW. Like all VistaVision films, this one was \ meant to be shown in Perspecta Stereophonic Sound where the mono dialog track was \ meant to be channelled to three different directions, making it directional, while \ the separate mono music + sound effects track was generally directed to all three \ speakers at the same time. The results fooled the viewers into thinking everything \ was in true stereo and the reproduction of the music was usually in very high fidelity. \ Maybe the soundtrack used on the DVD is a mono reduction of those two separate tracks \ that has squandered that fidelity and maybe the DVD can be issued again with better \ results in some kind of 4.0 presentation. When they do, very little electronic \ restoration work will be needed to make the image absolutely perfect. \ But let's concentrate on the positive: This film is a summit of visual \ splendour and its sets, costumes, colour photography, composition and lighting \ achieve, in every single scene, wonders of artistry, creativity and delicacy \ But let's concentrate on the positive: This film is a summit of visual \ splendour and its sets, costumes, colour photography, composition and lighting \ achieve, in every single scene, wonders of artistry, creativity and delicacy \ that will probably never be equalled. Suffice it to say that it has, \ among many other treasures, a sunrise duel scene in the snow that still has viewers \ wondering whether it was shot outdoors or in a studio and that will have them wondering foreverhsgkhgkshgu.\r\n"; #define countof(a) (sizeof(a) / sizeof(*(a))) #define bufsize1 (countof(txbuf1)-1) uint8_t rxbuf1[bufsize1] = {0}; bool spi_flash_test(void) { if (!spi_flash_is_init()) { return false; } const unsigned int sector_count = spi_flash_get_sector_count(); const unsigned int sector_size = spi_flash_get_sector_size(); const unsigned int total_size = spi_flash_get_total_size(); printf("Present: %u sectors, %u bytes per sector (%u bytes total)\r\n", sector_count, sector_size, total_size); for (uint16_t i = 0; i < sector_count; i++) { printf("sector: %u/%u ", i, sector_count); spi_flash_erase_sector(i * sector_size, 0); spi_flash_write(i * sector_size, txbuf1, bufsize1, 0); memset(rxbuf1, 0, bufsize1); spi_flash_read(i * sector_size, rxbuf1, bufsize1, 0); if (memcmp(txbuf1, rxbuf1, bufsize1) != 0) { printf("fail\r\n"); return false; } printf("ok\r\n"); } printf("\r\nDone\r\n"); return true; } #endif