|
| 1 | +--- |
| 2 | +title: Guide to GIGA R1 Dual Cores |
| 3 | +description: Learn how to access and control the M4 and M7 cores on the GIGA R1 |
| 4 | +author: Karl Söderby |
| 5 | +tags: [Dual Core, M4, M7] |
| 6 | +--- |
| 7 | + |
| 8 | +The GIGA R1's [STM32H747XI](static/resources/datasheets/stm32h747xi.pdf) has two cores, the M4 and the M7. Each core can be programmed individually, with M7 acting as the main processor, and the M4 as a co-processor. |
| 9 | + |
| 10 | +The M7 is referred to as the main processor due its superior hardware features, as well as it is required to run to boot the M4 core (you boot the M4 from within the M7). |
| 11 | + |
| 12 | +These two cores can run applications in parallel, for example, running a servo motor on one core, and a display on another, without blocking each other. In a single core, such operations would slow down the program, resulting in lesser performance. |
| 13 | + |
| 14 | +The M4 and M7 cores are programmed with separate sketches, using the same serial port. In the Arduino IDE, you can select the core you want to program, and then upload the sketch you want to run on that specific core. |
| 15 | + |
| 16 | +## Hardware & Software Needed |
| 17 | + |
| 18 | +- [GIGA R1 WiFi](/hardware/giga-r1-wifi) |
| 19 | +- [Arduino IDE](https://www.arduino.cc/en/software) |
| 20 | +- Arduino GIGA Core installed.\* |
| 21 | + |
| 22 | +***\*For instructions on how to install the GIGA Core, follow the [Getting Started with GIGA R1 guide](/tutorials/giga-r1-wifi/giga-getting-started).*** |
| 23 | + |
| 24 | +## Programming M4/M7 |
| 25 | + |
| 26 | +Programming the cores is done via the Arduino IDE, in a special interface that appears only when you **select the Arduino GIGA R1 board** from the board menu. |
| 27 | + |
| 28 | +### Partitioning The Flash Memory |
| 29 | + |
| 30 | +To allocate memory for the M4, the flash memory can be partitioned. This is done by navigating to **Tools > Flash Split** in the IDE. |
| 31 | + |
| 32 | + |
| 33 | + |
| 34 | +- **2MB M7 + M4 in SDRAM (default)** - this option is the default configuration, which is for programming the M7 only. This allocates no memory to the M4. |
| 35 | +- **1.5MB M7 + 0.5MB M4** - useful when larger amount of memory is required on the M7. |
| 36 | +- **1MB M7 + 1MB M4** - useful when you need to balance the memory equally between the M4 and M7 cores. |
| 37 | + |
| 38 | +***It is required to use option 2 or 3 if you intend to program the M4 via the IDE, as the default option provides no memory allocation for the M4.*** |
| 39 | + |
| 40 | +### Target Core |
| 41 | + |
| 42 | +To select the core you want to program, navigate to **Tools > Target Core** in the IDE. |
| 43 | + |
| 44 | + |
| 45 | + |
| 46 | +Here you can choose between: |
| 47 | +- **Main Core** - this is the M7 core, the main processor on the board. |
| 48 | +- **M4 Co-processor** - this is the M4 core, the co-processor on the board. |
| 49 | + |
| 50 | +### Uploading |
| 51 | + |
| 52 | +As both cores share the same serial port, choosing the **Flash Split** + **Target Core** is required so that the program is uploaded to the correct core. |
| 53 | + |
| 54 | +Uploading is no different than to any other Arduino board: simply click the upload button and wait for it to finish. |
| 55 | + |
| 56 | +### Booting M4 Core |
| 57 | + |
| 58 | +The M4 core does not boot by itself as it requires interaction from the M7 core. This boot function is built into the `RPC` library, and needs to be included in the sketch uploaded to the M7: |
| 59 | + |
| 60 | +```arduino |
| 61 | +#include <RPC.h> |
| 62 | +
|
| 63 | +void setup() { |
| 64 | + RPC.begin(); //boots M4 |
| 65 | +} |
| 66 | +void loop(){ |
| 67 | +} |
| 68 | +``` |
| 69 | + |
| 70 | +Once the M4 is booted from the M7, both cores will run in parallel, much like two Arduinos sharing the same board. |
| 71 | + |
| 72 | +### Writing Over Existing Sketch |
| 73 | + |
| 74 | +Uploading new sketches works the same as a typical upload procedure. The new sketch will overwrite the current sketch running on the core you upload to. |
| 75 | + |
| 76 | +## Limitations |
| 77 | + |
| 78 | +The M7 and M4 cores are two separate cores, and when initialized, they will continue to execute their corresponding program. |
| 79 | + |
| 80 | +In this section you will find some known limitations of using the two parallel cores. |
| 81 | + |
| 82 | +### Booting M4 |
| 83 | + |
| 84 | +As mentioned in the previous section, the M4 requires to be booted from the M7, by using the `RPC.begin()` method. If this is not included, the M4 will not boot. |
| 85 | + |
| 86 | +### Serial Communication |
| 87 | + |
| 88 | +Serial communication is not available by default on the M4 core. A work around for this is by sending data using the `RPC` library, and printing it from the M7 core. To achieve this, see the following examples: |
| 89 | + |
| 90 | +**M4 Sketch** |
| 91 | + |
| 92 | +```arduino |
| 93 | +#include <RPC.h> |
| 94 | +
|
| 95 | +void setup() { |
| 96 | + RPC.begin(); |
| 97 | +} |
| 98 | +
|
| 99 | +void loop() { |
| 100 | + // put your main code here, to run repeatedly: |
| 101 | + RPC.println("Hello World!"); |
| 102 | +} |
| 103 | +``` |
| 104 | + |
| 105 | +**M7 Sketch** |
| 106 | + |
| 107 | +```arduino |
| 108 | +#include <RPC.h> |
| 109 | +
|
| 110 | +void setup() { |
| 111 | + // put your setup code here, to run once: |
| 112 | + Serial.begin(9600); |
| 113 | + RPC.begin(); |
| 114 | +} |
| 115 | +
|
| 116 | +void loop() { |
| 117 | + String buffer = ""; |
| 118 | + while (RPC.available()) { |
| 119 | + buffer += (char)RPC.read(); |
| 120 | + } |
| 121 | +
|
| 122 | + if (buffer.length() > 0) { |
| 123 | + Serial.print(buffer); |
| 124 | + } |
| 125 | +} |
| 126 | +``` |
| 127 | + |
| 128 | +***Note that both of these sketches needs to be uploaded to their corresponding cores.*** |
| 129 | + |
| 130 | +### Advanced DAC/ADC On M4 |
| 131 | + |
| 132 | +The advanced DAC/ADC features using the [Arduino_AdvancedAnalog](https://github.com/bcmi-labs/Arduino_AdvancedAnalog/tree/main/examples/Advanced) library is not available on the M4. |
| 133 | + |
| 134 | +## Methods of Programming |
| 135 | + |
| 136 | +Programming the M4 and M7 cores is straightforward, but can be complicated to track. Having a strategy for how you want to build your dual core applications is key. |
| 137 | + |
| 138 | +In this section we introduce the "single" and "multiple" sketch approach, and the pros and cons of each method. |
| 139 | + |
| 140 | +### Single Sketch Approach |
| 141 | + |
| 142 | +The single sketch approach means writing a single sketch that is **uploaded to both cores** each time a change is made. In the sketch, we can keep track of what each core does by using simply by querying the core used with a simple function: |
| 143 | + |
| 144 | +```arduino |
| 145 | +String currentCPU() { |
| 146 | + if (HAL_GetCurrentCPUID() == CM7_CPUID) { |
| 147 | + return "M7"; |
| 148 | + } else { |
| 149 | + return "M4"; |
| 150 | + } |
| 151 | +} |
| 152 | +``` |
| 153 | + |
| 154 | +With this function, we check whether the M4 or M7 is running, and we can write code for each of the core like this: |
| 155 | + |
| 156 | +```arduino |
| 157 | + if (currentCPU() == "M4") { |
| 158 | + //run M4 code |
| 159 | + } |
| 160 | +
|
| 161 | + if (currentCPU() == "M7") { |
| 162 | + //run M7 code |
| 163 | + } |
| 164 | +``` |
| 165 | + |
| 166 | +The pros of using this approach is that you can write all code in a single file, therefore, revisioning code, as well as the provisioning is easier to manage. |
| 167 | + |
| 168 | +The cons of using this approach is that you will run out of program memory faster. You will also upload code to the cores that will never execute (the M7 code will not execute on M4 and vice versa). |
| 169 | + |
| 170 | +### Multiple Sketch Approach |
| 171 | + |
| 172 | +The multiple sketch approach means developing two separate sketches, one for each core. This does not require the use of the `HAL_GetCurrentCPUID()` to retrieve what core you are using, you can instead just write the sketch as you would normally do. |
| 173 | + |
| 174 | +The pros of using this approach is that the code you write is optimized only for one core, and this saves a lot of program memory. |
| 175 | + |
| 176 | +The cons is to manage the versions becomes harder, and while flashing the board, you'd need to keep track on which version is uploaded to which core. It is easier to upload to the wrong core by accident using this approach, but you have more optimized code. |
| 177 | + |
| 178 | +## Use Cases |
| 179 | + |
| 180 | +There are a number of cases where running two cores in parallel brings an advantage. Mainly, it allows one to develop code to run simultaneously, each performing their own individual tasks. |
| 181 | + |
| 182 | +In all modern computers, including yours, you have several cores each occupied with a number of task, in order to speed things up. This is particularly useful in blocking operations such as: |
| 183 | +- Controlling a servo motor, |
| 184 | +- Loading a display, |
| 185 | +- Connecting to a network. |
| 186 | + |
| 187 | +### Choosing Core |
| 188 | + |
| 189 | +Simply speaking, the M7 should always run your main program, or the most intensive program. It is overall a faster processor that reads memory and executes instructions faster. |
| 190 | + |
| 191 | +For example, you should be running network applications on the M7, while you do sensor readings on the M4. |
| 192 | + |
| 193 | +***To get a more detailed view on the differences between M4 and M7, see [Arm Cortex-M Processor Comparison Table](https://developer.arm.com/documentation/102787/latest).*** |
| 194 | + |
| 195 | +### Wi-Fi / Bluetooth® |
| 196 | + |
| 197 | +Wi-Fi and Bluetooth® applications are best run on the M7, as they are more demanding. Lower level tasks, such as controlling relays, reading sensor data and so forth, can be distributed to the M4 core instead. |
| 198 | + |
| 199 | +### Displays |
| 200 | + |
| 201 | +As the M7 is faster, it is best to run display sketches on the M7 core. Displays have a lot of blocking operations, and it is a good idea to separate the display's functionalities and other operations we want to perform. |
| 202 | + |
| 203 | +Running the display application on the M7 leaves the M4 free for other applications, such as motor control. Particularly useful when building projects where you need to control a motor from a display. |
| 204 | + |
| 205 | +### Robotics |
| 206 | + |
| 207 | +For robotics projects, separating the motor control **between the cores** can be beneficial. For example, servo control is a blocking operation, so if you are running several servos at the same time, performance can be reduced. |
| 208 | + |
| 209 | +It can also be distributed so that one core handles servo motors, and one handles stepper motors, if you are using multiple types of motors. |
| 210 | + |
| 211 | +### Sensors |
| 212 | + |
| 213 | +Sensor readings in itself does not matter much which core you use. If you are simply running some tests, it is good to run it on the M7, as you are able to print the results using `Serial.print()` (not available on M4, only through RPC). |
| 214 | + |
| 215 | +When used in relation to a e.g. a display, it is good practice to read sensors on the M4 core and on the M7, fetch the result and display it. |
0 commit comments