همانطور که میدانید در بسیاری از پروژهها ما نیاز به استفاده از حافظه جانبی داریم. بهعنوانمثال فرض کنید ردیابی طراحی کردهایم و میخواهیم هر وقت اتصال به اینترنت قطع شد دادههای GPS را ذخیره کنیم و بعد از برقراری اتصال تمام دادهها را یکجا به سرور منتقل کنیم. اما ممکن است تا چندین روز اتصال اینترنت قطع باشد و حجم دادهها بسیار زیاد شود. همچنین به دلیل محدودیت قیمت نمیتوانیم از حافظههای با حجم و قیمت بالا مانند sd card ها استفاده کنیم و حافظههای eeprom نیز حجم خیلی کمی دارند در این صورت میتوانیم از حافظههایی مانند w25qxx استفاده کنیم که حجمهایی در رنج مگابایت دارند. از دیگر کاربردهای SpiFlash میتوان به ذخیره صوت و تصاویر گرافیکی و سیستمهایی که دیتالاگر داخلی دارند اشاره کرد. در این آموزش قصد داریم کار با ایسی های حافظه در STM32 را برای شما شرح داده، ابتدا به راهاندازی SpiFlash میپردازیم و سپس FileSystem مناسب میکروکنترلر انتخاب کرده و روی حافظه جانبی راهاندازی میکنیم.
کار با ایسی های حافظه (spi flash) چیست؟
حافظههای FLASH از نسل EEPROM ها هستن اما با این تفاوت که در حافظههای EEPROM ما کنترل حافظهها بهصورت بایت بایت راداریم، درصورتیکه در حافظههای FLASH مدارات کنترل انفرادی بایت به بایت حذفشدهاند و فقط میتوانیم حافظه را بهصورت مجموعهای از بایتها (صفحه) مدیریت کنیم. اینکار باعث شده هزینه تمامشده کمتر شود.
در ادامه آموزش کار با ایسی های حافظه در STM32 به شناخت خانواده ایسی w25qxx میپردازیم.
مشخصات w25qxx
- جریان مصرفی کمتر از ۴ میلی آمپر
- قابلیت نوشتن و خواندن بیش از ۱۰۰۰۰۰ بار
- بیش از ۲۰ سال زمان نگهداری اطلاعات
- سرعت انتقال داده بیش از 75MB/s
ساختار حافظه در w25qxx
خانه های حافظه در آیسیهای فلش به سه صورت می باشند: بلوک، سکتور و صفحه
همانطور که در تصویر مشاهده میکنید کل حافظه w25qxx به بلوکهای 64KB تقسیم میشود و هر بلوک به 16 سکتور 4KB سپس هر سکتور به 16 صفحه 256 بایتی تقسیم میشود.
این ایسی در حجمهای مختلف ساختهشده است:
- W25Q80: 8M-bit / 1M -byte (1,048,576)
- W25Q16: 16M-bit / 2M-byte (2,097,152)
- W25Q32: 32M-bit / 4M-byte (4,194,304)
W25q16 دارای ظرفیت 16مگابیت که برابر است با 2 مگابایت (16Mb/8=2MB):
- تعداد بلوکها: مقدار کل حافظه آیسی تقسیمبر مقدار 64 کیلوبایت 32 بلوک
- تعداد سکتورها: 16 سکتور به ازای هر بلوک: 512=16*32
- تعداد صفحهها: مقدار حافظه هر سکتور تقسیمبر 256 بایت که میشود 16 صفحه به ازای هر سکتور: با 8192=16*512
محدودیت های ایسی w25qxx
در حافظه فلش به دلیل استفاده از مدارات کمتر، دیگر دسترسی مستقیم به تکتک بایتها وجود ندارد و باید بهصورت مجموعه (صفحه به صفحه) آنها را کنترل کرد.
برای مثال اگر ما بخواهیم بایت بیستم از حافظه را بخوانیم چون این بایت در صفحه صفر است باید کل این صفحه را که 256 بایت است را بخوانیم و سپس درون یک متغیر 256 بایتی بریزیم بعد از بایت دهم استفاده کنیم. در نوشتن نیز اینگونه است.
همچنین نمیتوانیم دوبار روی یک صفحه بنویسیم ابتدا باید اطلاعات را پاککنیم و سپس بنویسیم..
در این ایسی قادر نیسیتم اطلاعات را بهصورت بایت به بایت پاککنیم حداقل باید یک سکتور 4 کیلوبایتی را پاککنیم.
فرض کنید دادههای مختلفی داریم و میخواهیم این دادهها را ذخیره کنیم و ادیت کنیم. با توجه به محدودیتهای این ایسی اگر بخواهیم داده را مرتباً پاککنیم و تغییر دهیم کار سختی را در پیش خواهیم داشت، راهحل این مشکل استفاده از FileSystem است که بتوانیم داخل حافظه فایل ایجاد کنیم و توابعی جهت ایجاد فایل و تغییر یا پاک کردن آنها داشته باشیم.
littleFs چیست؟
فایل سیستم های معروف مانند fatfs حجم ram زیادی از میکرو خواهند گرفت اما فایل سیستمهایی هم هستند که مخصوص استفاده در میکروکنتر طراحیشدهاند مانند littleFS.
همچنین علاوه بر spi flash از littleFs میتوان برای ایجاد FileSystem در Flash داخلی میکروکنترلر نیز استفاده کرد.
در ادامه میتوانید منابع مصرفشده توسط دو فایل سیستم littleFs و fatFs را مقایسه کنید:
کدنویسی و ارتباط با W25Q16 توسط میکروکنترلر stm32
ابتدا به بررسی نحوه اتصال سختافزاری w25q به میکروکنترکر stm32f10X میپردازیم:
- Cs پایه انتخاب ایسی است اگر 0 باشد ایسی فعال میشود.
- Wp پایه نوشتن و محافظت ورودی (اگر این پایه صفر باشد ما فقط قابلیت خواندن از آیسی راداریم و درصورتیکه این پایه یک باشد ما قابلیت خواندن و نوشتن از داخل آیسی راداریم)
- RESET پایه ریست آیسی که با صفر فعال میشود.
- CLK ,Do ,DI پایههای ارتباط SPI جهت کنترل آیسی میباشند.
نحوه اتصال حافظه فلش به میکروکنترلر
پایههای RESET و WP را درصورتیکه نیازی به کنترل نداشته باشید میتوانید به مثبت VCC متصل کنید.
راه اندازی ریجستری SPI در میکروکنتر stm32f030k6t6:
void spi_ini(){ uint32_t sh; CLEAR_BIT(SPI1->CR1,SPI_CR1_SPE); sh=1; sh <<= 3; SPI1->CR1=sh; sh = 3; sh <<= 8; SPI1->CR2=sh; SET_BIT(SPI1->CR2,SPI_CR2_SSOE); SET_BIT(SPI1->CR1,SPI_CR1_MSTR); SET_BIT(SPI1->CR1,SPI_CR1_SPE); }
بهعنوانمثال جهت خواندن Device_ID و Manufact_id ابتدا کد هگزادسیمال 90 را ارسال میکنیم و سپس در 24 بیت آدرس 0 ارسال میکنیم و پسازآن ایسی اطلاعات را برای ما ارسال میکند.
و یا برای خواندن page ابتدا دستور Read Data (03h) ارسال میکنیم سپس 24 بیت آدرس صفحهای که قرار است خوانده شود را ارسال میکنیم و درنهایت میتوانیم 256 بایت دیتا آن صفحه را بخوانیم.
توابع راه اندازی w25qxx
خواندن device id:
void W25Q_Read_Manufact_Device_ID()} clear_CS_W25Q; SPI_w25q(W25Q_ManufactDeviceID); SPI_w25q(0x00); SPI_w25q(0x0<0); SPI_w25q(0x00); W25Q.ID_Manufacturer = SPI_w25q(0x00); W25Q.ID_device = SPI_w25q(0x00); set_CS_W25Q; }
پاک کردن سکتور 4 کیلوبایتی:
void W25Q_EraseSector4KB(unsigned long int address) } static unsigned char Data1=0,Data2=0,Data3=0; address=address*4096; Data1= (address>>16); Data2= (address>>8); Data3= (address); W25Q_Enable_Write(); W25Q_WaitBusy(); clear_CS_W25Q; SPI_w25q(W25Q_SectorErase); SPI_w25q(Data1); SPI_w25q(Data2); SPI_w25q(Data3); set_CS_W25Q; W25Q_WaitBusy(); {
خواندن page:
- ReadAddr (شماره صفحه)
- *pBuffer (ارایه دادهها)
- NumByteToRead (تعداد بایت هایی که باید خوانده شوند)
void W25Q_ReadPage(uint8_t *pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead)} uint16_t i; clear_CS_W25Q; SPI_w25q(W25Q_ReadData); SPI_w25q((uint8_t)((ReadAddr) >> 16)); SPI_w25q((uint8_t)((ReadAddr) >> 8)); SPI_w25q((uint8_t)ReadAddr); for (i = 0; i < NumByteToRead; i++) pBuffer[i] = SPI_w25q(0); set_CS_W25Q; {
نوشتن page:
- WriteAddr (شماره صفحه)
- *pBuffer (ارایه دادهها)
- NumByteToRead (تعداد بایت هایی که باید نوشته شوند)
void W25Q_WritePage(uint8_t *pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)} uint16_t i; W25Q_Enable_Write(); clear_CS_W25Q; SPI_w25q(W25Q_PageProgram); SPI_w25q((uint8_t)((WriteAddr) >> 16)); SPI_w25q((uint8_t)((WriteAddr) >> 8)); SPI_w25q((uint8_t)WriteAddr); for (i = 0; i < NumByteToWrite; i++)SPI_w25q(pBuffer[i]); set_CS_W25Q; W25Q_WaitBusy(); {
سایر توابعی که در کد نهایی استفاده شدهاند:
void W25Q_Read_StatusReg() // خواندن رجیستر های وضعیت ایسی
void W25Q_WaitBusy(void) // انتظار تا پایان زمانی که ایسی مشغول ذخیره کردن یا پاک کردن دادهها است.
چگونه میتوان با سرعت بالاتری با ایسی ارتباط برقرار کرد؟!
با چندیدن روش میتوان با ایسی ارتباط برقرار کرد ازجمله Fast Read، dual Read، quad read و..
کاربردیترین رجیستر ایسی کدام است؟!
مهمترین رجیستر ایسی، رجیستر وضعیت1 (Status register 1) میباشد، که به کمکان میتوانید
وضعیت، رایت کردن، مشغولی، وضعیتهای امنیتی ایسی و.. را ببینید.
در قسمت بعدی آموزش کار با ایسی های حافظه در STM32، ابتدا با کانفیگ کردن lfs اشنا میشویم. و بعد از ریدایرکت کردن تابع printf به uart میکرو به سراغ راهاندازی و دیباگ lfs میرویم.
منبع: سیسوگ