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 _stack_end;
/****************************************************************
* Basic interrupt handlers
****************************************************************/
// Initial code entry point - invoked by the processor after a reset
void
ResetHandler(void)
static void __noreturn
reset_handler_stage_two(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;
__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
uint32_t count = (&_data_end - &_data_start) * 4;
@ -45,6 +73,18 @@ ResetHandler(void)
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);
// 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.
#include "board/internal.h" // __CORTEX_M
#include "irq.h" // irqstatus_t
void
@ -36,6 +37,10 @@ irq_restore(irqstatus_t flag)
void
irq_wait(void)
{
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");
}
@ -43,3 +48,26 @@ 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
static void
canbus_send_blocking(uint32_t id, uint32_t len, uint8_t *data)
// Available commands and responses
#define CANBUS_CMD_QUERY_UNASSIGNED 0x00
#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 (;;) {
int ret = canbus_send(id, len, data);
int ret = canbus_send(CANBUS_ID_ADMIN_RESP, 7, send);
if (ret >= 0)
return;
}
}
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
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 (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)
if (len < 8)
return;
canbus_send_blocking(CANBUS_ID_UUID_RESP, sizeof(canbus_uuid), canbus_uuid);
}
static void
can_process_set_id(uint32_t id, uint32_t len, uint8_t *data)
{
// compare my UUID with packet to check if this packet mine
if (memcmp(&data[2], canbus_uuid, sizeof(canbus_uuid)) == 0) {
canbus_assigned_id = data[0] | (data[1] << 8);
canbus_set_dataport(canbus_assigned_id);
uint32_t newid = can_decode_nodeid(data[7]);
if (can_check_uuid(id, len, data)) {
if (newid != canbus_assigned_id) {
canbus_assigned_id = newid;
canbus_set_filter(canbus_assigned_id);
}
} else if (newid == canbus_assigned_id) {
can_id_conflict();
}
}
// Handle an "admin" command
static void
can_process(uint32_t id, uint32_t len, uint8_t *data)
{
if (id == canbus_assigned_id) {
if (len)
canboot_process_rx(id, len, data);
else
can_process_ping(id, len, data);
} else if (id == CANBUS_ID_UUID) {
if (len)
can_process_reset(id, len, data);
else
can_process_uuid(id, len, data);
} else if (id==CANBUS_ID_SET) {
can_process_set_id(id, len, data);
if (!len)
return;
switch (data[0]) {
case CANBUS_CMD_QUERY_UNASSIGNED:
can_process_query_unassigned(id, len, data);
break;
case CANBUS_CMD_SET_NODEID:
can_process_set_nodeid(id, len, data);
break;
}
}
@ -158,12 +179,23 @@ can_process(uint32_t id, uint32_t len, uint8_t *data)
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
canbus_notify_rx(void)
{
canbus_rx_wake = 1;
}
// Task to process incoming commands and admin messages
void
canbus_rx_task(void)
{
@ -178,6 +210,9 @@ canbus_rx_task(void)
int ret = canbus_read(&id, data);
if (ret < 0)
break;
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)
{
memcpy(canbus_uuid, uuid, sizeof(canbus_uuid));
// Send initial message
can_process_uuid(0, 0, NULL);
canbus_notify_rx();
}
void
canbus_shutdown(void)
{
canbus_notify_tx();
canbus_notify_rx();
}

View File

@ -3,24 +3,22 @@
#include <stdint.h> // uint32_t
#define CANBUS_ID_UUID 0x321
#define CANBUS_ID_SET 0x322
#define CANBUS_ID_UUID_RESP 0x323
#define CANBUS_ID_ADMIN 0x3f0
#define CANBUS_ID_ADMIN_RESP 0x3f1
#define CANBUS_UUID_LEN 6
// callbacks provided by board specific code
int canbus_read(uint32_t *id, 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 can_init(void);
// canbus.c
void canbus_notify_tx(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);
// canboot prototypes
void can_init(void);
void canbus_tx_task(void);
void canbus_rx_task(void);
uint8_t canbus_tx_clear(void);