Dokumentasi TL;DR: menyatakan bahwa saya harus mengaktifkan wilayah memori tertentu di mikrokontroler sebelum saya dapat menggunakannya. Namun, saya dapat menggunakannya sebelum mengaktifkannya, atau bahkan setelah menonaktifkannya. Bagaimana ini mungkin?


Saat ini saya sedang mengembangkan aplikasi untuk mikrokontroler STM32H743. Saya tidak mengerti bagaimana RAM tampaknya bekerja dengan benar saat jam dinonaktifkan.

MCU ini memiliki banyak memori, tersebar di beberapa domain daya:

  • Dalam domain D1 memiliki ITCMRAM + DTCMRAM + AXI SRAM (64 + 128 + 512 kB)
  • Dalam domain D2 memiliki SRAM1 + SRAM2 + SRAM3 (128 + 128 + 32 kB)
  • Dalam domain D3 memiliki SRAM4 + Backup SRAM (64 + 4 kB)

Saya ingin menggunakan SRAM1. Dalam manual referensi (RM0433 Rev. 7) dinyatakan pada halaman 366 bahwa:

Jika CPU ingin menggunakan memori yang terletak di domain D2 (SRAM1, SRAM2 dan SRAM3), CPU harus mengaktifkannya.

Pada pengaturan register di halaman 452 dijelaskan bagaimana melakukan ini:

Register Jam RCC AHB2 (RCC_AHB2ENR):

SRAM1EN: Blok SRAM1 diaktifkan
Atur dan atur ulang dengan perangkat lunak. Saat disetel, bit ini menunjukkan bahwa SRAM1 dialokasikan oleh CPU. Itu menyebabkan domain D2 menjadi pertimbangkan juga mode operasi CPU, yaitu menjaga domain D2 di DRun saat CPU when di CRun.
0: Jam antarmuka SRAM1 dinonaktifkan. (default setelah reset)
1: Jam antarmuka SRAM1 diaktifkan.

Jadi, nilai default (setelah reset) adalah 0, yang berarti antarmuka SRAM1 dinonaktifkan.

Dalam utas ini di forum Komunitas STM, pertanyaannya adalah mengapa RAM D2 tidak bekerja dengan benar dan solusinya adalah mengaktifkan jam RAM D2. Cara "benar" untuk melakukannya adalah di SystemInit() (bagian dari STM32H7 HAL). Di system_stm32h7xx.c kita dapat menemukan bagian kode berikut:

/************************* Miscellaneous Configuration ************************/
/*!< Uncomment the following line if you need to use initialized data in D2 domain SRAM (AHB SRAM)
 */
// #define DATA_IN_D2_SRAM

(...)

void SystemInit(void)
{
    (...)
#if defined(DATA_IN_D2_SRAM)
    /* in case of initialized data in D2 SRAM (AHB SRAM) , enable the D2 SRAM clock (AHB SRAM clock)
     */
#    if defined(RCC_AHB2ENR_D2SRAM3EN)
    RCC->AHB2ENR |= (RCC_AHB2ENR_D2SRAM1EN | RCC_AHB2ENR_D2SRAM2EN | RCC_AHB2ENR_D2SRAM3EN);
#    elif defined(RCC_AHB2ENR_D2SRAM2EN)
    RCC->AHB2ENR |= (RCC_AHB2ENR_D2SRAM1EN | RCC_AHB2ENR_D2SRAM2EN);
#    else
    RCC->AHB2ENR |= (RCC_AHB2ENR_AHBSRAM1EN | RCC_AHB2ENR_AHBSRAM2EN);
#    endif /* RCC_AHB2ENR_D2SRAM3EN */

    tmpreg = RCC->AHB2ENR;
    (void)tmpreg;
#endif /* DATA_IN_D2_SRAM */
    (...)
}

Jadi, untuk menggunakan D2 SRAM, makro DATA_IN_D2_SRAM harus ditentukan (atau Anda harus mengaktifkan jam secara manual menggunakan __HAL_RCC_D2SRAM1_CLK_ENABLE()).

Namun, Saya tidak menetapkan makro ini, dan bahkan ketika saya menonaktifkan jam secara manual, RAM tampaknya berfungsi dengan baik.

Tugas utama saya (saya menjalankan FreeRTOS, dan ini adalah satu-satunya tugas saat ini) adalah seperti ini:

void main_task(void * argument)
{
    __HAL_RCC_D2SRAM1_CLK_DISABLE();
    __HAL_RCC_D2SRAM2_CLK_DISABLE();
    __HAL_RCC_D2SRAM3_CLK_DISABLE();
    mem_test(); // expected to fail, but runs successfully
    for (;;) {}
}

Tes memori sepenuhnya mengisi D2 SRAM dengan data yang diketahui, kemudian menghitung CRC di atasnya. KKR benar. Saya sudah memverifikasi bahwa buffer benar-benar ditempatkan di D2 SRAM (alamat memori 0x30000400 berada dalam kisaran 0x30000000-0x3001FFFF dari SRAM1). Nilai RCC->AHB2ENR dikonfirmasi menjadi 0 (semua jam dinonaktifkan). Saya juga mengkonfirmasi bahwa alamat RCC->AHB2ENR adalah 0x580244DC, sebagaimana dinyatakan dalam lembar data.

Cache data dinonaktifkan.

Apa yang kulewatkan di sini? Mengapa memori ini dapat dibaca dan ditulis ketika jam dinonaktifkan?


PERBARUI: Atas permintaan, berikut adalah kode tes memori saya, dari mana saya menyimpulkan bahwa memori dapat ditulis dan dibaca dengan sukses:

// NB: The sections are defined in the linker script.
static char test_data_d1[16] __attribute__((section(".RAM_D1_data"))) = "Test data in D1";
static char test_data_d2[16] __attribute__((section(".RAM_D2_data"))) = "Test data in D2";
static char test_data_d3[16] __attribute__((section(".RAM_D3_data"))) = "Test data in D3";

static char buffer_d1[256 * 1024ul] __attribute__((section(".RAM_D1_bss")));
static char buffer_d2[256 * 1024ul] __attribute__((section(".RAM_D2_bss")));
static char buffer_d3[ 32 * 1024ul] __attribute__((section(".RAM_D3_bss")));

static void mem_test(void)
{
    // Fill the buffers each with a different test pattern.
    fill_buffer_with_test_data(buffer_d1, sizeof(buffer_d1), test_data_d1);
    fill_buffer_with_test_data(buffer_d2, sizeof(buffer_d2), test_data_d2);
    fill_buffer_with_test_data(buffer_d3, sizeof(buffer_d3), test_data_d3);

    uint32_t crc_d1 = crc32b((uint8_t const *)buffer_d1, sizeof(buffer_d1));
    uint32_t crc_d2 = crc32b((uint8_t const *)buffer_d2, sizeof(buffer_d2));
    uint32_t crc_d3 = crc32b((uint8_t const *)buffer_d3, sizeof(buffer_d3));

    printf("CRC buffer_d1 = 0x%08lX\n", crc_d1);
    printf("CRC buffer_d2 = 0x%08lX\n", crc_d2);
    printf("CRC buffer_d3 = 0x%08lX\n", crc_d3);

    assert(0xC29DFAED == crc_d1); // Python: hex(binascii.crc32(16384 * b'Test data in D1\0'))
    assert(0x73B70C2A == crc_d2); // Python: hex(binascii.crc32(16384 * b'Test data in D2\0'))
    assert(0xC30AE71E == crc_d3); // Python: hex(binascii.crc32(2048 * b'Test data in D3\0'))
}
6
wovano 19 November 2020, 12:25

1 menjawab

Jawaban Terbaik

Setelah banyak pengujian dan penyelidikan saya menemukan bahwa SRAM D2 dinonaktifkan (seperti yang didokumentasikan dan diharapkan) dalam aplikasi minimal menggunakan SysTick dan hanya beberapa LED untuk membuat hasil tes terlihat. Namun, saat menggunakan pengatur waktu (TIM1) alih-alih SysTick, atau saat mengaktifkan USART, SRAM D2 juga diaktifkan, bahkan ketika saya tidak mengaktifkannya dalam kode saya. Bahkan, menambahkan salah satu dari baris kode berikut secara implisit akan mengaktifkan SRAM D2:

__HAL_RCC_TIM1_CLK_ENABLE();
__HAL_RCC_USART3_CLK_ENABLE();

Dukungan STM telah mengkonfirmasi perilaku ini:

D2 SRAM diaktifkan segera setelah periferal di D2 diaktifkan. Ini berarti bahwa Jika Anda mengaktifkan jam untuk setiap periferal yang terletak di domain D2 (AHB1, AHB2, APB1 dan APB2), SRAM D2 akan aktif meskipun RCC->AHB2ENR adalah 0.

Saya masih mencari sumber yang dapat dipercaya (panduan referensi) di mana perilaku ini didokumentasikan, tetapi tampaknya merupakan penjelasan yang masuk akal.

Dalam praktiknya, saya pikir ini berarti bahwa SRAM D2 akan hampir selalu diaktifkan secara otomatis sehingga Anda tidak perlu mempedulikannya, setidaknya untuk kasus penggunaan yang paling umum (misalnya saat menggunakan periferal apa pun atau pengontrol DMA). Hanya bila Anda ingin menggunakan SRAM D2 tetapi tidak ada periferal D2, Anda harus mengaktifkan jam SRAM secara manual. Ini juga berlaku untuk kode startup, di mana (jika Anda memilih untuk menerapkan ini) SRAM D2 akan diinisialisasi sebelum periferal mana pun diaktifkan.

3
wovano 7 Desember 2020, 10:28