看板 C_and_CPP 關於我們 聯絡資訊
在克服 exception handling 的編譯問題後, 可以試試看呼叫 std::vector。mycpp.cpp L150 ~ L153 是熟悉的 vector 用法, 若能在 bare metal 上用上這個, 多美好阿! 老是 用固定大小的 array, 彈性不夠, 覺得很不爽。 在使用了 vector 之後, 會有很多 undefined symbol, mycpp.cpp L22 ~ L84 把他們一 一補上, 你說 vector 為什麼會和 _write 有關係? 我也不知道, 反正補上就是了。 由於在 bare metal 環境並沒有類似 malloc 的記憶體配置 function (你應該不會預期 有這樣的 function 可以用), 而這種會自己長大的容器一定是需要這種操作的, 那該怎 麼辦呢? 從 toolchain library 補上 malloc/free, new/delete 這些東西, 這個可能工程大了點 , 我改用另外一個途徑, 使用自己的 allocator, 所以要先寫一個 allocator。 看來好像也是一個大工程, 不過有現成的可以抄, 我就抄過 (就是常常被詬病的 copy/paste) 來了 (mycpp.cpp L88 ~ 140)。再把原本的 malloc 換成我自己的 mymalloc 就成了。 一開始的 mymalloc 只是回傳一個固定的記憶體位址, L86 的 memarea, 看起來很簡單也 很可疑, 不過的確可以正常運作。 void *mymalloc(u32 size) { return memarea; } mycpp.cpp 1 #include "stm32.h" 2 3 #include "mem.h" 4 5 #include <vector> 6 7 int print(int i) 8 { 9 i+=1; 10 } 11 12 int print(char c) 13 { 14 c-=1; 15 } 16 17 int print(const char *str) 18 { 19 } 20 21 22 void *dso_handle_; 23 void *__dso_handle; 24 25 extern "C" void _exit() 26 { 27 } 28 29 char brk_area[10240]; 30 31 extern "C" char *_sbrk(char *increment) 32 { 33 char *ptr = brk_area; 34 return ptr; 35 } 36 37 extern "C" 38 int _kill(int a, int b) 39 { 40 return a; 41 } 42 43 extern "C" 44 int _getpid() 45 { 46 int i; 47 return i; 48 } 49 50 extern "C" 51 int _write(int fd, const void *buf, int count) 52 { 53 } 54 55 extern "C" 56 int open(const char *pathname, int flags, int mode) 57 { 58 } 59 60 extern "C" 61 int _isatty(int fd) 62 { 63 } 64 65 66 extern "C" 67 int _close(int fd) 68 { 69 } 70 71 extern "C" 72 int _fstat(int fd, struct stat *buf) 73 { 74 } 75 76 extern "C" 77 int _read(int fd, void *buf, int count) 78 { 79 } 80 81 extern "C" 82 int _lseek(int fd, int offset, int whence) 83 { 84 } 85 86 static char memarea[10240]; 87 88 template <class T> 89 class my_allocator 90 { 91 public: 92 typedef int size_type; 93 typedef int difference_type; 94 typedef T* pointer; 95 typedef const T* const_pointer; 96 typedef T& reference; 97 typedef const T& const_reference; 98 typedef T value_type; 99 100 my_allocator() {} 101 my_allocator(const my_allocator&) {} 102 103 104 105 pointer allocate(size_type n, const void * = 0) { 106 T* t = (T*) mymalloc(n * sizeof(T)); 107 print("used my_allocator to allocate at address "); 108 print((int)t); 109 print("\r\n"); 110 111 return t; 112 } 113 114 void deallocate(void* p, size_type) { 115 if (p) { 116 myfree(p); 117 print("used my_allocator to deallocate at address "); 118 print((int)p); 119 print("\r\n"); 120 } 121 } 122 123 pointer address(reference x) const { return &x; } 124 const_pointer address(const_reference x) const { return &x; } 125 my_allocator<T>& operator=(const my_allocator&) { return *this; } 126 void construct(pointer p, const T& val) 127 { new ((T*) p) T(val); } 128 void destroy(pointer p) { p->~T(); } 129 130 size_type max_size() const { return int(-1); } 131 132 template <class U> 133 struct rebind { typedef my_allocator<U> other; }; 134 135 template <class U> 136 my_allocator(const my_allocator<U>&) {} 137 138 template <class U> 139 my_allocator& operator=(const my_allocator<U>&) { return *this; } 140 }; 141 142 void mymain(void) 143 { 144 #if 1 145 char a, b, c , d, e, f; 146 //std::vector<int, __gnu_cxx::new_allocator<int> > vec; 147 std::vector<char, my_allocator<char> > vec; 148 print(35); 149 print('A'); 150 for (int i=0 ; i < 5 ; ++i) 151 { 152 vec.push_back(i); 153 } 154 a = vec[0]; 155 b = vec[1]; 156 c = vec[2]; 157 d = vec[3]; 158 e = vec[4]; 159 160 char z=a+b+c+d; 161 162 while(1); 163 #endif 164 } 165 當然這個實在是太蠢了, 也會有一些問題, vector 在記憶體不夠的情況下, 會以 1, 2, 4, 8 的大小去配置需要的記憶體 (和書上寫的一樣耶!)。若是 vector<int> 就是 1*4, 2*4, 4*4, 8*4 去配置記憶體, 所以在某個情況下, 那個寫死的大小就會不夠用了。 所以我開發了一個相對不那麼蠢的, 對, 其實還是很蠢, 不過簡單, 又具有實用性, 還可 以驗證如果配置不到需要的記憶體, 會怎麼辦? 你一定很少看到 vector 要不到記憶體的 情況吧? mem.cpp 1 #include <stdio.h> 2 3 const int PAGE = 64; 4 const int HEAP_SIZE = PAGE*1024; 5 char heap[HEAP_SIZE]; 6 unsigned char mem_area[PAGE]; 7 int free_index = 0; 8 9 void print_memarea() 10 { 11 printf("free_index: %d\n", free_index); 12 for (int i = 0 ; i < PAGE ; ++i) 13 { 14 if (i % 8 == 0) 15 printf("\n"); 16 printf("%02d ", mem_area[i]); 17 } 18 printf("\n"); 19 } 20 21 // size: 1 means 1K, size max is 64 22 void *mymalloc(unsigned char size) 23 { 24 if (free_index + size > PAGE) 25 { 26 return 0; 27 } 28 char * ptr = heap + free_index * 1024; 29 #if 0 30 printf("xx free_index: %d\n", free_index); 31 printf("xx heap: %p\n", heap); 32 printf("xx ptr: %p\n", ptr); 33 #endif 34 *(mem_area + free_index) = size; 35 36 for (int i = 1 ; i < size ; ++i) 37 *(mem_area + free_index + i) = 1; 38 39 free_index += size; 40 return (void*)ptr; 41 } 42 43 void myfree(void *ptr) 44 { 45 int index = ((char *)ptr - heap) / 1024; 46 unsigned char size = *mem_area; 47 for (int i=0 ; i < size ; ++i) 48 *(mem_area + i) = 0; 49 } mem.cpp 從 64k 的 heap 分配記憶體, 很蠢的只有分配, 無法再度使用 myfree 回收的 記憶體。不過實作就容易多了。 RESULT 1 2 used my_allocator to allocate at address 0x804c6e0n: 1 size: 4 (+) 3 used my_allocator to allocate at address 0x804d6e0n: 2 size: 8 (+) 4 used my_allocator to deallocate at address 0x804c6e0 (-) 5 used my_allocator to allocate at address 0x804f6e0n: 4 size: 16 (+) 6 used my_allocator to deallocate at address 0x804d6e0 (-) 7 used my_allocator to allocate at address 0x80536e0n: 8 size: 32 (+) 8 used my_allocator to deallocate at address 0x804f6e0 (-) 9 cannot alloc memory 10 terminate called after throwing an instance of 'std::bad_alloc' 11 what(): std::bad_alloc 12 Aborted 以目前的記憶體管理設計, 當 vector 要以 32 去要記憶體時, 就會不夠用, 這時候 allocate 就會丟出 std::bad_alloc() (RESULT L11)。 RESULT 是在 linux 平台下的測試結果, 再搬到 stm32f4-discovery 上測試, 可以正常 的使用 vec.push_back(0) vec.push_back(1) vec.push_back(2) vec.push_back(3) vec.push_back(4) 不過由於在 stm32f4-discovery 不能丟出 std::bad_alloc(), 我得想個辦法處理要不到 記憶體的情況, 否則, vector 就不威了, 處理方式也很簡單, 印出訊息然後無窮回圈。 stm32f4-discovery sram 只有 192k, 很小的。 目前 github 的版本已經稍做改良, 可以用更細緻的方式配置記憶體, myfree 也會去回 收用過的記憶體, 當然還是比不上一般作業系統的的精緻度。 這是 gcc malloc_allocator 的實作, L98 也是使用 malloc, 並丟出 bad_alloc exception。 gcc-4.9.2/libstdc++-v3/include/ext/malloc_allocator.h 1 // Allocator that wraps "C" malloc -*- C++ -*- 2 3 // Copyright (C) 2001-2014 Free Software Foundation, Inc. 4 // 5 // This file is part of the GNU ISO C++ Library. This library is free 6 // software; you can redistribute it and/or modify it under the 7 // terms of the GNU General Public License as published by the 8 // Free Software Foundation; either version 3, or (at your option) 9 // any later version. 10 11 // This library is distributed in the hope that it will be useful, 12 // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 // GNU General Public License for more details. 15 16 // Under Section 7 of GPL version 3, you are granted additional 17 // permissions described in the GCC Runtime Library Exception, version 18 // 3.1, as published by the Free Software Foundation. 19 20 // You should have received a copy of the GNU General Public License and 21 // a copy of the GCC Runtime Library Exception along with this program; 22 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23 // <http://www.gnu.org/licenses/>. 24 25 /** @file ext/malloc_allocator.h 26 * This file is a GNU extension to the Standard C++ Library. 27 */ 28 29 #ifndef _MALLOC_ALLOCATOR_H 30 #define _MALLOC_ALLOCATOR_H 1 31 32 #include <cstdlib> 33 #include <new> 34 #include <bits/functexcept.h> 35 #include <bits/move.h> 36 #if __cplusplus >= 201103L 37 #include <type_traits> 38 #endif 39 40 namespace __gnu_cxx _GLIBCXX_VISIBILITY(default) 41 { 42 _GLIBCXX_BEGIN_NAMESPACE_VERSION 43 44 using std::size_t; 45 using std::ptrdiff_t; 46 47 /** 48 * @brief An allocator that uses malloc. 49 * @ingroup allocators 50 * 51 * This is precisely the allocator defined in the C++ Standard. 52 * - all allocation calls malloc 53 * - all deallocation calls free 54 */ 55 template<typename _Tp> 56 class malloc_allocator 57 { 95 // NB: __n is permitted to be 0. The C++ standard says nothing 96 // about what the return value is when __n == 0. 97 pointer 98 allocate(size_type __n, const void* = 0) 99 { 100 if (__n > this->max_size()) 101 std::__throw_bad_alloc(); 102 103 pointer __ret = static_cast<_Tp*>(std::malloc(__n * sizeof(_Tp))); 104 if (!__ret) 105 std::__throw_bad_alloc(); 106 return __ret; 107 } 148 149 _GLIBCXX_END_NAMESPACE_VERSION 150 } // namespace 151 152 #endif 以下是在 stm32 模擬器的完整範例: https://github.com/descent/progs/tree/master/mem_alloc/mem.h https://github.com/descent/progs/tree/master/mem_alloc/mem.cpp https://github.com/descent/stm32_p103_demos/tree/master/demos/uart_echo/myvec commit 317bde9c68f38eab73969a9526247dfb6bd1a870 output 1 descent@debianlinux:myvec$ /media/2/qemu_stm32/arm-softmmu/qemu-system-arm -display sdl -M stm32-p103 -kernel myvec.bin -nographic 2 STM32_UART: UART1 clock is set to 0 Hz. 3 STM32_UART: UART1 BRR set to 0. 4 STM32_UART: UART1 Baud is set to 0 bits per sec. 5 STM32_UART: UART2 clock is set to 0 Hz. 6 STM32_UART: UART2 BRR set to 0. 7 STM32_UART: UART2 Baud is set to 0 bits per sec. 8 STM32_UART: UART3 clock is set to 0 Hz. 9 STM32_UART: UART3 BRR set to 0. 10 STM32_UART: UART3 Baud is set to 0 bits per sec. 11 STM32_UART: UART4 clock is set to 0 Hz. 12 STM32_UART: UART4 BRR set to 0. 13 STM32_UART: UART4 Baud is set to 0 bits per sec. 14 STM32_UART: UART5 clock is set to 0 Hz. 15 STM32_UART: UART5 BRR set to 0. 16 STM32_UART: UART5 Baud is set to 0 bits per sec. 17 STM32_UART: UART5 clock is set to 0 Hz. 18 STM32_UART: UART5 BRR set to 0. 19 STM32_UART: UART5 Baud is set to 0 bits per sec. 20 STM32_UART: UART4 clock is set to 0 Hz. 21 STM32_UART: UART4 BRR set to 0. 22 STM32_UART: UART4 Baud is set to 0 bits per sec. 23 STM32_UART: UART3 clock is set to 0 Hz. 24 STM32_UART: UART3 BRR set to 0. 25 STM32_UART: UART3 Baud is set to 0 bits per sec. 26 STM32_UART: UART2 clock is set to 0 Hz. 27 STM32_UART: UART2 BRR set to 0. 28 STM32_UART: UART2 Baud is set to 0 bits per sec. 29 STM32_UART: UART1 clock is set to 0 Hz. 30 STM32_UART: UART1 BRR set to 0. 31 STM32_UART: UART1 Baud is set to 0 bits per sec. 32 LED Off 33 CLKTREE: HSI Output Change (SrcClk:None InFreq:8000000 OutFreq:8000000 Mul:1 Div:1 Enabled:1) 34 CLKTREE: HSI/2 Output Change (SrcClk:HSI InFreq:8000000 OutFreq:4000000 Mul:1 Div:2 Enabled:1) 35 CLKTREE: SYSCLK Output Change (SrcClk:HSI InFreq:8000000 OutFreq:8000000 Mul:1 Div:1 Enabled:1) 36 CLKTREE: HCLK Output Change (SrcClk:SYSCLK InFreq:8000000 OutFreq:8000000 Mul:1 Div:1 Enabled:1) 37 STM32_RCC: Cortex SYSTICK frequency set to 8000000 Hz (scale set to 125). 38 STM32_RCC: Cortex SYSTICK ext ref frequency set to 1000000 Hz (scale set to 1000). 39 CLKTREE: PCLK1 Output Change (SrcClk:HCLK InFreq:8000000 OutFreq:8000000 Mul:1 Div:1 Enabled:1) 40 CLKTREE: PCLK2 Output Change (SrcClk:HCLK InFreq:8000000 OutFreq:8000000 Mul:1 Div:1 Enabled:1) 41 CLKTREE: HSE Output Change (SrcClk:None InFreq:8000000 OutFreq:8000000 Mul:1 Div:1 Enabled:1) 42 CLKTREE: HSE/2 Output Change (SrcClk:HSE InFreq:8000000 OutFreq:4000000 Mul:1 Div:2 Enabled:1) 43 CLKTREE: PLLXTPRE Output Change (SrcClk:HSE InFreq:8000000 OutFreq:8000000 Mul:1 Div:1 Enabled:1) 44 CLKTREE: PCLK1 Output Change (SrcClk:HCLK InFreq:8000000 OutFreq:4000000 Mul:1 Div:2 Enabled:1) 45 CLKTREE: PLLCLK Output Change (SrcClk:PLLXTPRE InFreq:8000000 OutFreq:72000000 Mul:9 Div:1 Enabled:1) 46 CLKTREE: SYSCLK Output Change (SrcClk:PLLCLK InFreq:72000000 OutFreq:72000000 Mul:1 Div:1 Enabled:1) 47 CLKTREE: HCLK Output Change (SrcClk:SYSCLK InFreq:72000000 OutFreq:72000000 Mul:1 Div:1 Enabled:1) 48 STM32_RCC: Cortex SYSTICK frequency set to 72000000 Hz (scale set to 13). 49 STM32_RCC: Cortex SYSTICK ext ref frequency set to 9000000 Hz (scale set to 111). 50 CLKTREE: PCLK1 Output Change (SrcClk:HCLK InFreq:72000000 OutFreq:36000000 Mul:1 Div:2 Enabled:1) 51 CLKTREE: PCLK2 Output Change (SrcClk:HCLK InFreq:72000000 OutFreq:72000000 Mul:1 Div:1 Enabled:1) 52 CLKTREE: GPIOA Output Change (SrcClk:PCLK2 InFreq:72000000 OutFreq:72000000 Mul:1 Div:1 Enabled:1) 53 CLKTREE: AFIO Output Change (SrcClk:PCLK2 InFreq:72000000 OutFreq:72000000 Mul:1 Div:1 Enabled:1) 54 CLKTREE: UART2 Output Change (SrcClk:PCLK1 InFreq:36000000 OutFreq:36000000 Mul:1 Div:1 Enabled:1) 55 STM32_UART: UART2 clock is set to 36000000 Hz. 56 STM32_UART: UART2 BRR set to 0. 57 STM32_UART: UART2 Baud is set to 0 bits per sec. 58 STM32_UART: UART2 clock is set to 36000000 Hz. 59 STM32_UART: UART2 BRR set to 3750. 60 STM32_UART: UART2 Baud is set to 9600 bits per sec. 61 mymalloc: 1 byte(s) 62 used my_allocator to allocate at address 20002374 n: 1 sizeof(T): 1 63 mymalloc: 2 byte(s) 64 used my_allocator to allocate at address 20002774 n: 2 sizeof(T): 1 65 myfree: p 66 index: 0 67 size: 1 68 used my_allocator to free address 20002374 69 mymalloc: 4 byte(s) 70 used my_allocator to allocate at address 20002B74 n: 4 sizeof(T): 1 71 myfree: p 72 index: 1 73 size: 1 74 used my_allocator to free address 20002774 75 mymalloc: 8 byte(s) 76 used my_allocator to allocate at address 20002F74 n: 8 sizeof(T): 1 77 myfree: p 78 index: 2 79 size: 1 80 used my_allocator to free address 20002B74 81 0 82 1 83 2 84 3 85 4 86 87 ---------------- 88 free_index: 4 89 90 0 0 0 1 0 0 0 0 91 0 0 0 0 0 0 0 0 92 0 0 0 0 0 0 0 0 93 0 0 0 0 0 0 0 0 94 0 0 0 0 0 0 0 0 95 0 0 0 0 0 0 0 0 96 0 0 0 0 0 0 0 0 97 0 0 0 0 0 0 0 0 98 ================ ref: Using Custom Allocators ( http://goo.gl/vnB8ht ) blog 版本 http://descent-incoming.blogspot.tw/2015/05/bare-metal-programming-for-stm32f4.html // 本文使用 Blog2BBS 自動將Blog文章轉成縮址的BBS純文字 http://goo.gl/TZ4E17 // -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 180.217.230.19 ※ 文章網址: https://www.ptt.cc/bbs/C_and_CPP/M.1436231235.A.820.html
loveme00835: 這篇是在..? 07/09 22:45
descent: 在 bare-metal 環境下, 如何使用 vector 07/10 23:26