همانطور که میدانید در بسیاری از پروژهها ما نیاز به استفاده از حافظه جانبی داریم. بهعنوانمثال فرض کنید ردیابی طراحی کردهایم و میخواهیم هر وقت اتصال به اینترنت قطع شد دادههای 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 بایتی بریزیم بعد از بایت دهم استفاده کنیم. در نوشتن نیز اینگونه است.
شاید برای شما مفید باشد: آموزش FPGA
همچنین نمیتوانیم دوبار روی یک صفحه بنویسیم ابتدا باید اطلاعات را پاککنیم و سپس بنویسیم..
در این ایسی قادر نیسیتم اطلاعات را بهصورت بایت به بایت پاککنیم حداقل باید یک سکتور 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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 کیلوبایتی:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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 (تعداد بایت هایی که باید خوانده شوند)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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 (تعداد بایت هایی که باید نوشته شوند)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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 میرویم.
باتشکر از مهندس کاوه رفیعی جهت تهیه این آموزش
سلام
ممنون بابت مطلبی که اینجا نوشتید
نوشتید برای اینکه تو ی صفحه بخوای بنویسی اول باید اون صفحه پاک بشه ولی خودتون تو کدی که نوشتید این کارو رو انجام ندادید. اگه دلیلی داره بفرمایید لطفا.
سلام
چطور میشود روی این ای سی فلش اهنگ بریزیم و بوسیله میکرو پخش نماییم؟
سپاس
خوب فکر میکنم قبلا در موردش مطلب داشتیم
آموزش STM32 با توابع LL قسمت سی و سوم: لیست پخش در wave player
با تشکر از مطلب خوبتون.
لازم دونستم این نکته رو یاد آور بشم که کتابخونه littlefs متاسفانه thread-safe نیست و توی مساله استفاده بین تسک ها مشکلاتی رو بوجود میاره، بنظرم اموزش کتابخونه elm-chan رو بزارید که حتی دو حالت مختلف برای اپتیمایز کردن کداش داره که بنظرم میتونه جایگزین خوبی برای littlefs باشه.
با تشکر
خواهش میکنم.
ممنون از پیشنهادتون.
من که با این کتابخونه کار نکردم.
اگر بتونید خودتون آموزشی براش تهیه کنید که توی سایت با اسم خودتون منتشر کنیم که خیلی خوبه ، میتونید هم اطلاعات بیشتری بدید تا بررسیش کنیم
اگه لطف کنین یه راه ارتباطی معرفی کنید که بیشتر در ارتباط باشیم ممنون میشم
mahdi2001h.ir
خدا قوت .
واقعا عالییییی .
منتظر قسمت های بعدی هستیم .
تشکر ??
خواهش میکنم?
ممنون از تهیه این آموزش … جالبه که من برای کارهای خودم از همینها استفاده میکنم . یه نشکلی که دارم اینه که سرعت خواندن از این ای سی نهایتش به ریر ۷۰ مگ میرسه … بالاتر که میبرم ای سی هیچ اطلاعاتی نمیده … فکر کپم پیشفرض سرعت ارسال اطلاعات این ای سی پایینتره ولی درحالیکه طبق دیتاشیت تا ۱۰۴ مگ باید بیاد بالا … ممنون میشیم که تجربیات خودتون رو با ما درمیون میزارید.
ممنون از مطلب خوبتون. در ادامه نکته ای رو یادآور میشوم:
دو فایل سیستم خوب رو باهاشون آشنایی دارم:
اول: SPIFFS که مکانیزم wear دارد اما آنجا که اختصاصا برای NOR Flash نوشته شده، بلوکهای خراب را تشخیص نمیدهد. خوبیش آن است که حجم کمی در حدود چند صد بایت از حافظه را برای راهاندازی فایل سیستم و buffering اشغال میکند. ولی متاسفانه دیگر پشتیبانی نمیشود و اگر bugی داشت زحمت پیدا کردن و اصلاحش به عهده خودتان است.
دوم: littlefs که به روز است و پشتیبانی میشود. حجم بیشتری برای راهاندازی فایل سیستم از حافظه اشغال میکند اما قابلیت تشخیص بلوک خراب و wear و غیره را دارد. بسیار خوب document شده و اگر حوصله داشتید میتوانید به جزییات کتابخانهی آن کاملا اشراف پیدا کنید. شخصا این کتابخانه را پیشنهاد میدهم.
نسخهی آخرِ هر دو کتابخانهی بالا را از سایت github میتوانید دریافت کنید.
فکر میکنم مناسب هست در این بخش به نکته مهم wear leveling در حافظه های فلش اشاره کنید. در منابع فارسی خیلی کم به آن پرداخته شده است.
بسیار عالی و واضح بیان شده
??
بسیار عالی و پر کاربرد بود . لطفا قسمت بعدی هم منتشر شود
??
بله حتما
بسیار کامل و کاربردی ??
لطفا قسمت بعدی رو هرچی زودتر قرار بدید ?
لطف دارید?
بله حتما?