📜 ⬆️ ⬇️

We rewrite the arduino code for MSP430 using the example of nRF24_multipro, a project for managing toy multicopters


Before the start, I would like to immediately say that the code was not written by me and was taken from here . This program is written in the Arduino IDE and in conjunction with the arduino pro mini and nrf24l01 + allows you to control toy multicopters (with XN297 radio chips, nrf24l01 clones) from any control devices that have a PPM output. All information about supported multicopters can be found at the link above.
I decided to rewrite this code to control the Eachine H8 mini copter from the Radiolink AT9 hardware. For details, I ask under the cat.

MSP430 was chosen because it has a power supply of 3.3 volts, the supply voltage of nrf24l01 is also 3.3 volts, and I somehow like the MPS430 more. Inside the equipment are the contacts 3V3, OUT, GND, to which we will connect.

If there is no desire to disassemble the equipment, then you can connect to the coaching connector, but the voltage on it = battery voltage, so a voltage regulator is added to the circuit.


Let's get down to the code


First we will open the project in IDE Energia (Arduino IDE clone for MSP430 and other chips from TI) and try to compile it, but we immediately see a compilation error. This project uses additional libraries and access to registers, and the first thing you need to start with them. So, we proceed to a detailed analysis.

Libraries


We will edit the nRF24_multipro.ino file and start with include. This project uses the atomic and EEPROM libraries.
')

atomic


Remove the string
#include <util/atomic.h> 
and in the void update_ppm () function we remove
 ATOMIC_BLOCK(ATOMIC_RESTORESTATE) 
Instead of curly brackets we write
 __disable_interrupt(); 
and
 __enable_interrupt(); 

The ATOMIC_BLOCK () function turns off interrupts while the code is executed in its “body” and, depending on the parameter, turns on interrupts or restores the value of the interrupt flag to the state it was in before the ATOMIC_BLOCK () function was called.

Eeprom


There is no EEPROM memory in MSP430, but there is a FLASH memory and there is a MspFlash library for working with it. Therefore, remove the string
 #include <EEPROM.h> 
and add the MspFlash library (Sketch-> Import Library ... -> MspFlash), add to which segment of the FLASH memory we will write data
 #define flash SEGMENT_D 
In the function void selectProtocol () we change strings
 else current_protocol = constrain(EEPROM.read(ee_PROTOCOL_ID),0,PROTO_END-1); // update eeprom EEPROM.update(ee_PROTOCOL_ID, current_protocol); 
on
 // update eeprom Flash.write(flash+ee_PROTOCOL_ID, & current_protocol,1); 
We remove completely reading the protocol identifier (why, read below).
In the void set_txid (bool renew) function, you need to do a little more than replace two lines. In FLASH memory, we can only reset bits. To set the value 1 in FLASH memory, you need to erase the entire segment (then the value 1 will be written into it). This function (set_txid) is called earlier than selectProtocol, so we will delete the segment here.
It was:
 void set_txid(bool renew) { uint8_t i; for(i=0; i<4; i++) transmitterID[i] = EEPROM.read(ee_TXID0+i); if(renew || (transmitterID[0]==0xFF && transmitterID[1]==0x0FF)) { for(i=0; i<4; i++) { transmitterID[i] = random() & 0xFF; EEPROM.update(ee_TXID0+i, transmitterID[i]); } } } 

It became:
 void set_txid(bool renew) { uint8_t i; unsigned char p; for(i=0; i<4; i++) { Flash.read(flash+ee_TXID0+i,&p,1); transmitterID[i] =p; } Flash.read(flash+ee_PROTOCOL_ID,&p,1); current_protocol = constrain(p,0,PROTO_END-1); Flash.erase(flash); if(renew || (transmitterID[0]==0xFF && transmitterID[1]==0x0FF)) { for(i=0; i<4; i++) { transmitterID[i] = random(0xff) & 0xFF; p = transmitterID[i]; Flash.write(flash+ee_TXID0+i, &p,1); } }else{ for(i=0; i<4; i++) { p = transmitterID[i]; Flash.write(flash+ee_TXID0+i, &p,1); } } } 
Here we read the value of the transmitter identifiers and the protocol, erase the segment, and if a command is given to update the transmitter identifier, we write the new value, otherwise we write the old one. The FLASH memory byte with the flash + ee_PROTOCOL_ID address remained clean (0xFF), so we don’t read it in the selectProtocol () function, and immediately write the protocol identifier there.

Registers


First, let's deal with the pins. This project uses a software implementation of SPI, which uses macros to “jerk” with its legs through the registers.
Rewrite pin definitions
with
 #define PPM_pin 2 // PPM in //SPI Comm.pins with nRF24L01 #define MOSI_pin 3 // MOSI - D3 #define SCK_pin 4 // SCK - D4 #define CE_pin 5 // CE - D5 #define MISO_pin A0 // MISO - A0 #define CS_pin A1 // CS - A1 #define ledPin 13 // LED - D13 
on
 #define PPM_pin P1_5 // PPM in //SPI Comm.pins with nRF24L01 #define MOSI_pin P2_0 // MOSI #define SCK_pin P2_1 // SCK #define CE_pin P2_2 // CE #define MISO_pin P2_3 // MISO #define CS_pin P2_4 // CS #define ledPin P1_4 // LED 
and
 #define MOSI_on PORTD |= _BV(3) // PD3 #define MOSI_off PORTD &= ~_BV(3)// PD3 #define SCK_on PORTD |= _BV(4) // PD4 #define SCK_off PORTD &= ~_BV(4) // PD4 #define CE_on PORTD |= _BV(5) // PD5 #define CE_off PORTD &= ~_BV(5) // PD5 #define CS_on PORTC |= _BV(1) // PC1 #define CS_off PORTC &= ~_BV(1) // PC1 // SPI input #define MISO_on (PINC & _BV(0)) // PC0 
on
 #define MOSI_on P2OUT |= _BV(0)// P2_0 #define MOSI_off P2OUT &= ~_BV(0)// P2_0 #define SCK_on P2OUT |= _BV(1)// P2_1 #define SCK_off P2OUT &= ~_BV(1)// P2_1 #define CE_on P2OUT |= _BV(2)// P2_2 #define CE_off P2OUT &= ~_BV(2)// P2_2 #define CS_on P2OUT |= _BV(4)// P2_4 #define CS_off P2OUT &= ~_BV(4) // P2_4 // SPI input #define MISO_on (P2IN & _BV(3)) // P2_3 

In MK from ATMEL, the PORTx registers in MSP430 PxOUT are responsible for the output status. For the state of the input-registers PINx and PxIN, respectively. By the way, there is no _BV (x) function in IDE Energia, therefore we add it ourselves:
 #define _BV(val) 1<<val 
In the void setup () function, we change the values ​​of the pins of the analog inputs to the free ones with
 randomSeed((analogRead(A4) & 0x1F) | (analogRead(A5) << 5)); 
for example on
 randomSeed((analogRead(A0) & 0x1F) | (analogRead(A1) << 5)); 
In MSP430, the analog inputs A0, A1, A2, ..., A7 correspond to the P1_0, P1_1, P1_2, ..., P1_7 pins.
When connecting interrupt change
 attachInterrupt(PPM_pin - 2, ISR_ppm, CHANGE); 
on
 attachInterrupt(PPM_pin , ISR_ppm, CHANGE); 
In Arduino Uno, Nano, Mini, and others, on mega328 only 2 pins are available for connecting interrupts (2, 3) and in the attachInterrupt function, the first argument is the interrupt number, and not a pin like MSP430. Learn more about attachInterrupt () .

Timer


Change in void setup ()
 TCCR1A = 0; //reset timer1 TCCR1B = 0; TCCR1B |= (1 << CS11); //set timer1 to increment every 1 us @ 8MHz, 0.5 us @16MHz 
On
 TACTL = TASSEL_2 + ID_3 + MC_2 + TACLR; //16000000 / 8 
The timer is needed to determine the pulse duration in the PPM. We set it to direct counting with a frequency of 2 MHz (16 MHz clock frequency and a divisor by 8).
In the function void ISR_ppm () we change
 counterPPM = TCNT1; TCNT1 = 0; 
on
 counterPPM = TAR; TAR = 0; 
Registers TCNT1 and TAR timer counters.

random ()


I don’t know why, but the random () function is not called in Energia, but since we need a random single-byte number, we replace nRF24_multipro.ino and Bayang.ino in the files
 random() & 0xFF; 
on
 random(0xFF); 
and
 random() % 0x42; 
on
 random(0x41); 

???


And finally, in the MJX.ino file in the void MJX_bind () function, we add parentheses to the function call mjx_init2;
We compile the project and get a successful conclusion.

Project source code
Modified project code

To successfully transfer the program to another platform, you need to understand what, how and why it is performed in this code, understand the features of the connected libraries, assignment of registers and look more often into the compilation log for errors in the course of work.
Well, if you do it together for good, then you need to transfer the project to another development environment, connect hardware SPI and work only with registers, but this is a completely different story.

Source: https://habr.com/ru/post/392609/


All Articles