Берем картину мироздания и тупо смотрим, что к чему.
160us
-----
0x200F/0xE00 *
-----
160us
-----
0x2009/0xE00 *
0x2A26/0xE00 0xA867/0x00 0x35CC/0x00 *
0xAFF/0xE26 *
0x3026/0xE00 0xA867/0x00 0x35CC/0x00 *
0x10FF/0xE26 *
0x390B/0xE00 0xDFC4/0x00 0xA703/0x00 *
0x3EC9/0xE00 0x9AB0/0x00 0x61BB/0x00 0xAB9C/0x00 *
0x1EFF/0xEC9 *
0x3F4C/0xE00 0x846F/0x00 0x9C20/0x00 *
0x1FFF/0xE4C *
0x2607/0xE00 *
0x310F/0xE00 *
0x7FF/0x4040
0x2009/0x4000
0x61FF/0x40AA 0xFFFF/0xE62 0xFFFF/0x00 0xFFFF/0xBC 0xFFFF/0x7F7F 0xFFFF/0x201E 0xFFFF/0x4040 0xFFFF/0x00
0x2740/0x4E00
0xE200/0xE00
0x200F/0xE00
-------
0x2009/0xE00
0x2511/0xE00
0x200F/0xE00
0x7FF/0xE0E
write to 0x68 ack data: 0x6B 0x02
write to 0x68 ack data: 0x19 0x01
write to 0x68 ack data: 0x1A 0x01
write to 0x68 ack data: 0x1B 0x18
write to 0x68 ack data: 0x1C 0x18
write to 0x68 ack data: 0x1D 0x00
write to 0x68 ack data: 0x1E 0x0A
write to 0x68 ack data: 0x3B
read to 0x68 ack data: 0xFF 0xD3 0xFF 0x8A 0x08 0xF9 0x09 0xF9 0xFF 0x7F 0x00 0x24 0xFF 0xFE
write to 0x68 ack data: 0x3B
read to 0x68 ack data: 0xFF 0xD3 0xFF 0x8A 0x08 0xF9 0x09 0xF9 0xFF 0x7F 0x00 0x24 0xFF 0xFE
write to 0x68 ack data: 0x3B
read to 0x68 ack data: 0xFF 0xD3 0xFF 0x8A 0x08 0xF9 0x09 0xF9 0xFF 0x7F 0x00 0x24 0xFF 0xFE
{
"build": {
"cpu": "cortex-m0",
"extra_flags": "-DSTM32F031x4",
"f_cpu": "48000000L",
"mcu": "stm32f031k4",
"product_line": "STM32F031x4",
"variant": "STM32F0xx/F031K4"
},
"debug": {
"jlink_device": "STM32F031K4",
"openocd_target": "stm32f0x",
"svd_path": "STM32F031.svd"
},
"frameworks": [
"arduino",
"cmsis",
"stm32cube",
"libopencm3"
],
"name": "generic STM32F031K4",
"upload": {
"maximum_ram_size": 4096,
"maximum_size": 16384,
"protocol": "stlink",
"protocols": [
"jlink",
"cmsis-dap",
"stlink",
"blackmagic",
"serial"
]
},
"url": "https://www.hotmcu.com/stm32f030f4p6-minimum-systerm-boardcortexm0-p-208.html",
"vendor": "Generic"
}
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/cm3/nvic.h>
#include <libopencm3/cm3/systick.h>
#include <system.h>
volatile uint32_t TimeCounter;
void system_init(void)
{
rcc_clock_setup_in_hsi_out_48mhz(); // set STM32 to clock by 48MHz from HSI oscillator
TimeCounter=0;
systick_set_clocksource(STK_CSR_CLKSOURCE_AHB);
STK_CVR = 0; // clear counter
systick_set_reload(rcc_ahb_frequency / 1000); // Set up timer interrupt
systick_counter_enable();
systick_interrupt_enable();
}
void delay_us(uint16_t del_us)
{
uint32_t cnt = del_us << 2;
do
{
asm volatile("nop");
asm volatile("nop");
asm volatile("nop");
asm volatile("nop");
} while (--cnt);
}
void delay(uint32_t time)
{
TimeCounter = time;
while(TimeCounter != 0);
}
void sys_tick_handler(void)
{
if (TimeCounter |= 0) TimeCounter--;
}
void init_LEDs(void)
{
// Enable clocks to the GPIO subsystems
rcc_periph_clock_enable(RCC_GPIOB);
rcc_periph_clock_enable(RCC_GPIOA);
// LED OUTPUTS
gpio_mode_setup(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO2 | GPIO4 | GPIO12);
gpio_mode_setup(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO0 | GPIO2);
gpio_clear(GPIOA, GPIO2 | GPIO4 | GPIO12);
gpio_clear(GPIOB, GPIO0 | GPIO2);
}
void LedMask(uint8_t mask)
{
if (mask & 0x01) gpio_set(GPIOA, GPIO2); else gpio_clear(GPIOA, GPIO2);
if (mask & 0x02) gpio_set(GPIOA, GPIO4); else gpio_clear(GPIOA, GPIO4);
if (mask & 0x04) gpio_set(GPIOB, GPIO0); else gpio_clear(GPIOB, GPIO0);
if (mask & 0x08) gpio_set(GPIOA, GPIO12); else gpio_clear(GPIOA, GPIO12);
if (mask & 0x10) gpio_set(GPIOB, GPIO2); else gpio_clear(GPIOB, GPIO2);
}
void LedSet(uint8_t mask)
{
if (mask & 0x01) gpio_set(GPIOA, GPIO2);
if (mask & 0x02) gpio_set(GPIOA, GPIO4);
if (mask & 0x04) gpio_set(GPIOB, GPIO0);
if (mask & 0x08) gpio_set(GPIOA, GPIO12);
if (mask & 0x10) gpio_set(GPIOB, GPIO2);
}
void LedClear(uint8_t mask)
{
if (mask & 0x01) gpio_clear(GPIOA, GPIO2);
if (mask & 0x02) gpio_clear(GPIOA, GPIO4);
if (mask & 0x04) gpio_clear(GPIOB, GPIO0);
if (mask & 0x08) gpio_clear(GPIOA, GPIO12);
if (mask & 0x10) gpio_clear(GPIOB, GPIO2);
}
void LedToggle(uint8_t mask)
{
if (mask & 0x01) gpio_toggle(GPIOA, GPIO2);
if (mask & 0x02) gpio_toggle(GPIOA, GPIO4);
if (mask & 0x04) gpio_toggle(GPIOB, GPIO0);
if (mask & 0x08) gpio_toggle(GPIOA, GPIO12);
if (mask & 0x10) gpio_toggle(GPIOB, GPIO2);
}
#include <system.h>
main(void)
{
system_init();
init_LEDs();
while (1)
{
uint8_t mask = 1;
for(uint8_t i=0; i<5; i++)
{
LedMask(mask);
mask <<=1;
delay(500);
}
}
}
#include <UART.h>
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/usart.h>
#include <math.h>
void init_USART(void)
{
// only tx at PA2
rcc_periph_clock_enable(RCC_GPIOA);
rcc_periph_clock_enable(RCC_USART1);
// Setup GPIO pins for USART transmit.
gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO2);
gpio_set_af(GPIOA, GPIO_AF1, GPIO2);
// Setup USART parameters.
usart_set_baudrate(USART1, 115200);
usart_set_databits(USART1, 8);
usart_set_parity(USART1, USART_PARITY_NONE);
usart_set_stopbits(USART1, USART_CR2_STOPBITS_1);
usart_set_mode(USART1, USART_MODE_TX_RX);
usart_set_flow_control(USART1, USART_FLOWCONTROL_NONE);
usart_enable(USART1);
}
uint8_t num2sym(uint8_t symb)
{
symb &= 0x0F;
if (symb<10) symb+='0';
else symb+='A'-10;
return symb;
}
void tx_byte_UART(uint8_t c)
{
tx_UART('0');
tx_UART('x');
tx_UART(num2sym(c>>4));
tx_UART(num2sym©);
}
void tx_word_UART(uint16_t c)
{
tx_UART('0');
tx_UART('x');
tx_UART(num2sym(c>>12));
tx_UART(num2sym(c>>8));
tx_UART(num2sym(c>>4));
tx_UART(num2sym©);
}
void tx_UART(uint8_t c)
{
while ((USART_ISR(USART1) & USART_ISR_TXE)==0); // TX empty
usart_send(USART1, c);
}
void buff_UART(uint8_t *pointer, uint8_t length)
{
do
{
uint8_t data= *pointer;
tx_UART(num2sym(data>>4));
tx_UART(num2sym(data));
tx_UART(' ');
pointer++;
} while(--length);
tx_UART(0xa);
tx_UART(0xd);
}
void int2s(uint8_t *String, int16_t Data)
{
ldiv_t DivNum;
uint8_t * Pointer;
bool sign = false;
if(Data<0)
{
sign = true;
Data = -Data;
}
Pointer = String;
for(uint8_t i=0; i<5; i++) *Pointer++ = ' ';
*Pointer = 0;
Pointer = String+4;
for(uint8_t i=0; i<4; i++)
{
if (Data<10)
{
*Pointer--= (char)Data+'0';
break;
}
else
{
DivNum = ldiv(Data, 10);
*Pointer-- = (char)DivNum.rem+'0';
Data = DivNum.quot;
}
}
if (sign) *Pointer = '-';
}
void str2UART(uint8_t *pointer)
{
uint8_t maxl=16;
do
{
uint8_t data= *pointer;
if (data==0) break;
tx_UART(data);
pointer++;
} while(--maxl);
}
void int2UART(uint16_t Number)
{
uint8_t tx_buff[16];
int2s(tx_buff, Number);
str2UART(tx_buff);
}
#include <XN297.h>
#include <SPI.h>
#include <UART.h>
#include <system.h>
void CheckVoltage(void)
{
adc_read();
delay(100);
adc_read();
if (adc_read()<CODE_MIN)
{
for(uint8_t j=0; j<6; j++)
{
uint8_t mask = 1;
for(uint8_t i=0; i<5; i++)
{
LedMask(mask);
mask <<=1;
delay(100);
}
}
standby();
}
}
void TestRadio(void)
{
static bool binded = false;
uint16_t out16;
static uint8_t blink_cnt=0;
out16 = transfer_word_SPI(0x07, 0xFF);
if (out16 & 0x40)
{
if (binded) rx_pack();
else
{
bind();
binded = true;
LedClear(0x10);
}
buff_UART(rx_buff,16);
}
else
{
if (!binded)
{
blink_cnt++;
if (blink_cnt==50)
{
blink_cnt=0;
LedToggle(0x10);
}
}
}
delay(2);
}
int main(void)
{
system_init();
init_LEDs();
adc_init();
init_USART();
init_SPI();
init_XN297();
CheckVoltage();
uint8_t mask = 1;
for(uint8_t i=0; i<5; i++)
{
LedMask(mask);
mask <<=1;
delay(500);
}
while (1)
{
TestRadio();
}
}
uint8_t u8map(int16_t x, int16_t in_min, int16_t in_max, int16_t out_min, int16_t out_max)
{
return (x - in_min) *(out_max - out_min) / (in_max - in_min) + out_min;
}
int main(void)
{
system_init();
init_LEDs();
init_PWM();
init_SPI();
init_USART();
init_XN297();
bool binded = false;
while (1)
{
uint16_t out16;
out16 = transfer_word_SPI(0x07, 0xFF);
if (out16 & 0x40)
{
if (binded)
{
rx_pack();
buff_UART(rx_buff,16);
uint8_t status;
status = rx_buff[14];
if(status &0x04) gpio_set(GPIOA, GPIO2); else gpio_clear(GPIOA, GPIO2);
if(status &0x08) gpio_set(GPIOA, GPIO4); else gpio_clear(GPIOA, GPIO4);
if(status &0x10) gpio_set(GPIOA, GPIO12); else gpio_clear(GPIOA, GPIO12);
if(status &0x20) gpio_set(GPIOB, GPIO0); else gpio_clear(GPIOB, GPIO0);
if(status &0x40) gpio_set(GPIOB, GPIO2); else gpio_clear(GPIOB, GPIO2);
status = rx_buff[6];
status = u8map(status, 0, 0xff, 0, 100);
timer_set_oc_value(TIM1, TIM_OC1, status);
status = rx_buff[7];
status = u8map(status, 0x43, 0xbb, 0, 100);
timer_set_oc_value(TIM1, TIM_OC2, status);
status = rx_buff[8];
status = u8map(status, 0x43, 0xbb, 0, 100);
timer_set_oc_value(TIM2, TIM_OC1, status);
status = rx_buff[9];
status = u8map(status, 0x43, 0xbb, 0, 100);
timer_set_oc_value(TIM2, TIM_OC2, status);
}
else
{
bind();
binded = true;
}
}
delay(100);
}
}
cImu IMU;
uint8_t cout;
void TestImu(void)
{
IMU.readAccelData(); // Read the x/y/z adc values
IMU.readGyroData(); // Read the x/y/z adc values
IMU.Mahony_no_mag_Update();
delay(20);
cout++;
if (cout==50)
{
IMU.quater2euler();
cout=0;
int16_t Angles[3];
Angles[0] = (int16_t)(IMU.roll);
Angles[1] = (int16_t)(IMU.pitch);
Angles[2] = (int16_t)(IMU.yaw);
for(uint i=0; i<3; i++)
{
int2UART(Angles[i]);
tx_UART(' ');
}
tx_UART(0xa);
tx_UART(0xd);
}
}
int main(void)
{
system_init();
init_LEDs();
init_USART();
init_i2c();
IMU.resetMPU9250(); // Reset registers to default in preparation for device calibration
IMU.calibrateMPU9250(IMU.gyroBias, IMU.accelBias); // Calibrate gyro and accelerometers, load biases in bias registers
IMU.initMPU9250();
IMU.deltat = 0.02;
cout=0;
while(1) TestImu();
}
+53 |
1826
78
|
С одной стороны конечно хороший реверсинг, а с другой — зачем вот это двукратное упоминание про «а зачем это всё было — я вам не скажу», и отмазка про «длинный обзор» тут не актуальна — видали раз в 10 больше, от того-же Кирича.
Так что осталось такое себе кликбейтовское послевкусие. Извини ДонБатон, ничего личного, просто моё мнение.
-как?
-завтра расскажу…
© ничего личного, просто моё мнение
Умейте ждать, и не искать во всём кликбейт или подвох.
Интересный обзор и понятно дело что такой реверс быстро не делается, что по железу, что по софту.
P. S. Дон, спасибо за отличный обзор, с нетерпением буду ждать продолжения.
Например возможность дорабатывать прошивку и купив коптер за 10$, дать ему возможности, которые вам нужны, а не те, что сделали и ленивые китаясы.
Возможность прикрутить нормальную аппу, или вообще управлять с ББ и тд.
А ещё это просто интересно — разобраться как что-то сделано и работает.
У проца мозгов слишком мало
Стм32-103 это ну совсем ни о чем и копеечно
Если хотите дорабатывать прошивку — курите в сторону ardupilot или PX4, оно в исходниках на гитхабе
Это вам говорит человек, сделавший на спор на attiny опрос аналогового ик-приемника и одновременную работу WS-ленты. Тоже все говорили — «мощности проца не хватит, коды не будут распознаваться!», только на деле спорящим не мощности проца не хватает, а знаний.
Проц из обзора — это не топ стм-а, но имя мозги и зная асм и не полагаясь на сгенерированый идехой стартап-код и не копипастя со стэковерфлоу и гита из него можно выжать куда больше, чем выжали китайцы на данный момент. Если не умеете — то нефиг всех ровнять по себе.
А тинька, уважаемый, была дана для примера того, что можно сделать, когда все другие будут кричать, что «невозможно».
При том что я писал про квадр.
И предлагал вместо этого убогого китайского квадра заняться реально полезным делом — реверсинжиниринговать более интересный квадр DJI.
А вы влезли в тему про квадр со своей вшивотозной аттини доказывая что вы крутой квадростроитель. Если вы не про квадр то чего вы мне пишете то?
Напишите сами тогда более продвинутый мозг квадру чтобы мог летать по маршруту используя GPS. Вы я вижу специалист по самостоятельному написанию полетных контроллеров для квадрокоптеров :)
какими инструментами пользоваться? (осциллографа конечно же нет)
Все чипы изготавливаются в китае, но всё что есть на али — со следами лазерной гравировки.
Оригинальный чип имеет горячее тиснение краской.
И ещё — он жутко шумный, использовать без магнитометра нет смысла.
в проекте www.multi-module.org/basics/supported-protocols или www.deviationtx.com/wiki/supported_models посмотри, возможно будет тебе щасте =)
кстати, F0 процы читаются. только уметь надо.
Мне пока не нужно, но вдруг в копилочку знаний попадётся :)
Вы такое сами делали? Правда или это ваша фантазия?
Там есть цитата, на то, на что я комментарий писал.
Цитата, причем, вашего комментария — попробуйте разобрать буковки, тогда может и мой ответ дойдет :D
Попробуйте прочитать буковки о чем идет речь, а потом уж встревать.
Ииии… я жду от вас вами построенный квадрокоптер на аттини :)
12 килобайт! И летал и управлялся, находил цели и стрелял, и сам после убийства пилота возвращался на точку старта и садился.
Для тех кто программировал в СССР на ассемблере или в машинных кодах и этого было МНОГО!
Кстати вся игра с цветной 3Д графикой и генерацией бесконечных вселенных и планет, с симулятором космического истребителя, Элита на пк Синклер Спектрум занимала всего 48 килобайт!
Кстати, из-за картинки Elite грузилась дольше всех намного, учитывая всякие помехи, ещё и не спервого раза. А если вспомнить мигание света в то время, и сохранения на на магнитофон :)
Ах да. В конце-концов она, конечно же, занимала свои 42кб, ибо 6192 — видеопамять.
Автор принимает комиты если есть возможность протестить потом.