Collections on ARM Cortex

Hi guys,

I just recently started to use a Rust on the ARM microcontroller. Im staring up MCU in C and then pass controll to the Rust. Everything is going well, but I'm stuck on importing a libraries. How can I use a String?

I compiled libcore, liballoc, libstd_unicode and libcollections.

I put all compiled crates in the rust_libs folder and then compile with

rustc -Z no-landing-pads --target thumbv7m-none-eabi -g --emit obj --crate-type staticlib -L ../rust_libs/ -o ../Debug/Src/rust.o ../Src/main.rs

When I try to use String it gives me an error:

|
10 | name: String
| ^^^^^^ not found in this scope

Are you compiling with no_std? If so, you need to import String directly from alloc library, something like extern crate alloc, then use alloc::string::String.

Tangential question, why not pure Rust?

1 Like

You might find it a lot easier to use xargo, a wrapper around cargo designed by @japaric for cross compiling and working with microcontrollers. You could probably compile to a static library and then get your C compiler to compile that in and strip it all down.

Otherwise, as @idubrov mentioned, why not use Rust for everything? There are some really good articles on the net about using Rust on ARM devices.

2 Likes

Thank's for your answers. Yes I'm using no_std. I have tried to use a alloc crate, but it gives me another error.
error: no #[default_lib_allocator] found but one is required; is libstd not linked?
use of unstable library feature 'alloc': this library is unlikely to be stabilized in its current form or name (see issue #27783)

I will come back to this later, until then I will use str. Also I will have to work out how to use a libc crate for the c strings.

Why not pure Rust? Because I have to use FreeRTOS, LWIP, STM HAL libraries and some other. It would not be very wise to rewrite them. I'm very new to Rust, but I hope I will figure it out.

1 Like

Ah, I think I know why you're having troubles. Basically a no_std program is designed to run with the absolute bare minimum, this means it's been designed to assume there is no heap at all! The collections library requires a heap (String is a heap-allocated vector of bytes after all), so you need to have access to an allocator. That's what the error message is trying to tell you.

In embedded programs you will typically only ever use static strings (&str) and buffers on the stack, dynamic memory allocation isn't really a thing. So you don't need libcollections, libstd_unicode, and liballoc.

You'll most probably have issues pulling in the libc crate as well seeing as it's designed to be used with an OS and you're running on bare metal (lots of libc functions are wrappers around syscalls to the underlying OS).

What things from libcollections do you need? For example, if you want something like Vec, the arrayvec crate provides a Vec-like type which is backed by an array. There are also libraries available for the using other collections in a no_std environment.

It seems that I have to write a custom allocator to use any dynamic memory
https://doc.rust-lang.org/1.9.0/book/custom-allocators.html.

@Michael-F-Bryan You are right that it would be best not to use alloc, but sometimes it is useful. Maybe it is for better, I will be forced not to use it :slight_smile:

1 Like

As part of his blog series on writing a kernel in Rust (10/10 would recommend reading if you've got the time, by the way) @phil_opp made a simple linked list allocator, if you really need dynamic memory allocation then you could give that a shot.

I've found an allocator isn't as necessary as in desktop programming though. As one data point, a mate of mine actually worked at NASA as part of an internship, writing firmware for a project. After he got back I was chatting with him and he didn't know what malloc() was. so that may be an indicator of how much you need dynamically allocated things like String and Vec...

I came across another problem that I cannot solve

Imagine I have a C function void get_data(uint32_t max_size, struct data *d) where I will pass in max size of a buffer and pointer to the buffer. Data struct contains some fields and array:

struct data
{
  a: u8,
  b: u8,
  c: [u8, 256]
}

When I try to define an array this way then compiler is complaining

let mut buffer[data; 8] = [data {
  a: 0,
  b: 0,
  c: [0; 256]
}; 8];

error[E0277]: the trait bound data: std::marker::Copy is not satisfied

If I add a #[derive(Clone, Copy)] to the definition of the struct, then I get another error the trait std::clone::Cloneis not implemented for[u8; 256]`

How can I solve this? How can I define array of structs with array field in Rust to pass into C function to work as a buffer?