src: update generic files

Bring up generic files to accommodate the latest version of
Klipper.

Signed-off-by:  Eric Callahan <arksine.code@gmail.com>
This commit is contained in:
Eric Callahan 2022-04-11 17:18:24 -04:00
parent 72bde3bbf8
commit 73d7ddd5aa
No known key found for this signature in database
GPG Key ID: 7027245FBBDDF59A
5 changed files with 170 additions and 56 deletions

View File

@ -14,17 +14,45 @@ extern uint32_t _data_start, _data_end, _data_flash;
extern uint32_t _bss_start, _bss_end, _stack_start; extern uint32_t _bss_start, _bss_end, _stack_start;
extern uint32_t _stack_end; extern uint32_t _stack_end;
/**************************************************************** /****************************************************************
* Basic interrupt handlers * Basic interrupt handlers
****************************************************************/ ****************************************************************/
// Initial code entry point - invoked by the processor after a reset static void __noreturn
void reset_handler_stage_two(void)
ResetHandler(void)
{ {
// Disable SysTick irq (for some bootloaders that don't) int i;
// Clear all enabled user interrupts and user pending interrupts
for (i = 0; i < ARRAY_SIZE(NVIC->ICER); i++) {
NVIC->ICER[i] = 0xFFFFFFFF;
__DSB();
NVIC->ICPR[i] = 0xFFFFFFFF;
}
// Reset all user interrupt priorities
for (i = 0; i < ARRAY_SIZE(NVIC->IP); i++)
NVIC->IP[i] = 0;
// Disable SysTick interrupt
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk; SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk;
__DSB();
// Clear pending pendsv and systick interrupts
SCB->ICSR = SCB_ICSR_PENDSVCLR_Msk | SCB_ICSR_PENDSTCLR_Msk;
// Reset all system interrupt priorities
#if __CORTEX_M >= 7
for (i = 0; i < ARRAY_SIZE(SCB->SHPR); i++)
SCB->SHPR[i] = 0;
#else
for (i = 0; i < ARRAY_SIZE(SCB->SHP); i++)
SCB->SHP[i] = 0;
#endif
__DSB();
__ISB();
__enable_irq();
// Copy global variables from flash to ram // Copy global variables from flash to ram
uint32_t count = (&_data_end - &_data_start) * 4; uint32_t count = (&_data_end - &_data_start) * 4;
@ -45,6 +73,18 @@ ResetHandler(void)
for (;;) for (;;)
; ;
} }
// Initial code entry point - invoked by the processor after a reset
// Reset interrupts and stack to take control from bootloaders
void
ResetHandler(void)
{
__disable_irq();
// Explicitly load the stack pointer, jump to stage two
asm volatile("mov sp, %0\n bx %1"
: : "r"(&_stack_end), "r"(reset_handler_stage_two));
}
DECL_ARMCM_IRQ(ResetHandler, -15); DECL_ARMCM_IRQ(ResetHandler, -15);
// Code called for any undefined interrupts // Code called for any undefined interrupts

View File

@ -4,6 +4,7 @@
// //
// This file may be distributed under the terms of the GNU GPLv3 license. // This file may be distributed under the terms of the GNU GPLv3 license.
#include "board/internal.h" // __CORTEX_M
#include "irq.h" // irqstatus_t #include "irq.h" // irqstatus_t
void void
@ -36,10 +37,37 @@ irq_restore(irqstatus_t flag)
void void
irq_wait(void) irq_wait(void)
{ {
asm volatile("cpsie i\n wfi\n cpsid i\n" ::: "memory"); if (__CORTEX_M >= 7)
// Cortex-m7 may disable cpu counter on wfi, so use nop
asm volatile("cpsie i\n nop\n cpsid i\n" ::: "memory");
else
asm volatile("cpsie i\n wfi\n cpsid i\n" ::: "memory");
} }
void void
irq_poll(void) irq_poll(void)
{ {
} }
// Clear the active irq if a shutdown happened in an irq handler
void
clear_active_irq(void)
{
uint32_t psr;
asm volatile("mrs %0, psr" : "=r" (psr));
if (!(psr & 0x1ff))
// Shutdown did not occur in an irq - nothing to do.
return;
// Clear active irq status
psr = 1<<24; // T-bit
uint32_t temp;
asm volatile(
" push { %1 }\n"
" adr %0, 1f\n"
" push { %0 }\n"
" push { r0, r1, r2, r3, r4, lr }\n"
" bx %2\n"
".balign 4\n"
"1:\n"
: "=&r"(temp) : "r"(psr), "r"(0xfffffff9) : "r12", "cc");
}

View File

@ -0,0 +1,8 @@
#ifndef __GENERIC_ARMCM_TIMER_H
#define __GENERIC_ARMCM_TIMER_H
#include <stdint.h> // uint32_t
void udelay(uint32_t usecs);
#endif // armcm_timer.h

View File

@ -87,67 +87,88 @@ canboot_sendf(uint8_t* data, uint16_t size)
/**************************************************************** /****************************************************************
* CAN command handling * CAN "admin" command handling
****************************************************************/ ****************************************************************/
// Helper to retry sending until successful // Available commands and responses
static void #define CANBUS_CMD_QUERY_UNASSIGNED 0x00
canbus_send_blocking(uint32_t id, uint32_t len, uint8_t *data) #define CANBUS_CMD_SET_NODEID 0x01
#define CANBUS_RESP_NEED_NODEID 0x20
// Helper to verify a UUID in a command matches this chip's UUID
static int
can_check_uuid(uint32_t id, uint32_t len, uint8_t *data)
{ {
return len >= 7 && memcmp(&data[1], canbus_uuid, sizeof(canbus_uuid)) == 0;
}
// Helpers to encode/decode a CAN identifier to a 1-byte "nodeid"
static int
can_get_nodeid(void)
{
if (!canbus_assigned_id)
return 0;
return (canbus_assigned_id - 0x100) >> 1;
}
static uint32_t
can_decode_nodeid(int nodeid)
{
return (nodeid << 1) + 0x100;
}
static void
can_process_query_unassigned(uint32_t id, uint32_t len, uint8_t *data)
{
if (canbus_assigned_id)
return;
uint8_t send[8];
send[0] = CANBUS_RESP_NEED_NODEID;
memcpy(&send[1], canbus_uuid, sizeof(canbus_uuid));
// Send with retry
for (;;) { for (;;) {
int ret = canbus_send(id, len, data); int ret = canbus_send(CANBUS_ID_ADMIN_RESP, 7, send);
if (ret >= 0) if (ret >= 0)
return; return;
} }
} }
static void static void
can_process_ping(uint32_t id, uint32_t len, uint8_t *data) can_id_conflict(void)
{ {
canbus_send_blocking(canbus_assigned_id + 1, 0, NULL); canbus_assigned_id = 0;
canbus_set_filter(canbus_assigned_id);
// TODO: We should likely do something here, such as report back
} }
static void static void
can_process_reset(uint32_t id, uint32_t len, uint8_t *data) can_process_set_nodeid(uint32_t id, uint32_t len, uint8_t *data)
{ {
/*uint32_t reset_id = data[0] | (data[1] << 8); if (len < 8)
if (reset_id == canbus_assigned_id)
canbus_reboot();*/
}
static void
can_process_uuid(uint32_t id, uint32_t len, uint8_t *data)
{
if (canbus_assigned_id)
return; return;
canbus_send_blocking(CANBUS_ID_UUID_RESP, sizeof(canbus_uuid), canbus_uuid); uint32_t newid = can_decode_nodeid(data[7]);
} if (can_check_uuid(id, len, data)) {
if (newid != canbus_assigned_id) {
static void canbus_assigned_id = newid;
can_process_set_id(uint32_t id, uint32_t len, uint8_t *data) canbus_set_filter(canbus_assigned_id);
{ }
// compare my UUID with packet to check if this packet mine } else if (newid == canbus_assigned_id) {
if (memcmp(&data[2], canbus_uuid, sizeof(canbus_uuid)) == 0) { can_id_conflict();
canbus_assigned_id = data[0] | (data[1] << 8);
canbus_set_dataport(canbus_assigned_id);
} }
} }
// Handle an "admin" command
static void static void
can_process(uint32_t id, uint32_t len, uint8_t *data) can_process(uint32_t id, uint32_t len, uint8_t *data)
{ {
if (id == canbus_assigned_id) { if (!len)
if (len) return;
canboot_process_rx(id, len, data); switch (data[0]) {
else case CANBUS_CMD_QUERY_UNASSIGNED:
can_process_ping(id, len, data); can_process_query_unassigned(id, len, data);
} else if (id == CANBUS_ID_UUID) { break;
if (len) case CANBUS_CMD_SET_NODEID:
can_process_reset(id, len, data); can_process_set_nodeid(id, len, data);
else break;
can_process_uuid(id, len, data);
} else if (id==CANBUS_ID_SET) {
can_process_set_id(id, len, data);
} }
} }
@ -158,12 +179,23 @@ can_process(uint32_t id, uint32_t len, uint8_t *data)
static volatile uint8_t canbus_rx_wake; static volatile uint8_t canbus_rx_wake;
// Handle incoming data (called from IRQ handler)
void
canbus_process_data(uint32_t id, uint32_t len, uint8_t *data)
{
if (!id || id != canbus_assigned_id)
return;
canboot_process_rx(id, len, data);
canbus_notify_rx();
}
void void
canbus_notify_rx(void) canbus_notify_rx(void)
{ {
canbus_rx_wake = 1; canbus_rx_wake = 1;
} }
// Task to process incoming commands and admin messages
void void
canbus_rx_task(void) canbus_rx_task(void)
{ {
@ -178,7 +210,10 @@ canbus_rx_task(void)
int ret = canbus_read(&id, data); int ret = canbus_read(&id, data);
if (ret < 0) if (ret < 0)
break; break;
can_process(id, ret, data); if (id && id == canbus_assigned_id + 1)
can_id_conflict();
else if (id == CANBUS_ID_ADMIN)
can_process(id, ret, data);
} }
} }
@ -190,7 +225,12 @@ void
canbus_set_uuid(void *uuid) canbus_set_uuid(void *uuid)
{ {
memcpy(canbus_uuid, uuid, sizeof(canbus_uuid)); memcpy(canbus_uuid, uuid, sizeof(canbus_uuid));
canbus_notify_rx();
// Send initial message }
can_process_uuid(0, 0, NULL);
void
canbus_shutdown(void)
{
canbus_notify_tx();
canbus_notify_rx();
} }

View File

@ -3,24 +3,22 @@
#include <stdint.h> // uint32_t #include <stdint.h> // uint32_t
#define CANBUS_ID_UUID 0x321 #define CANBUS_ID_ADMIN 0x3f0
#define CANBUS_ID_SET 0x322 #define CANBUS_ID_ADMIN_RESP 0x3f1
#define CANBUS_ID_UUID_RESP 0x323
#define CANBUS_UUID_LEN 6 #define CANBUS_UUID_LEN 6
// callbacks provided by board specific code // callbacks provided by board specific code
int canbus_read(uint32_t *id, uint8_t *data); int canbus_read(uint32_t *id, uint8_t *data);
int canbus_send(uint32_t id, uint32_t len, uint8_t *data); int canbus_send(uint32_t id, uint32_t len, uint8_t *data);
void canbus_set_dataport(uint32_t id); void canbus_set_filter(uint32_t id);
void canbus_reboot(void); void canbus_reboot(void);
void can_init(void);
// canbus.c // canbus.c
void canbus_notify_tx(void); void canbus_notify_tx(void);
void canbus_notify_rx(void); void canbus_notify_rx(void);
void canbus_process_data(uint32_t id, uint32_t len, uint8_t *data);
void canbus_set_uuid(void *data); void canbus_set_uuid(void *data);
// canboot prototypes
void can_init(void);
void canbus_tx_task(void); void canbus_tx_task(void);
void canbus_rx_task(void); void canbus_rx_task(void);
uint8_t canbus_tx_clear(void); uint8_t canbus_tx_clear(void);