STM32+uIP+ENC28J60

ChibiOS public support forum for topics related to the STMicroelectronics STM32 family of micro-controllers.

Moderator: RoccoMarco

Post Reply
JonBAL
Posts: 3
Joined: Sun Jan 04, 2015 5:03 pm

STM32+uIP+ENC28J60

Post by JonBAL »

Greetings to all!
I have recently been using ChibiOS, and now I have to develop a project that unites: STM32F103 + ChibiOS + uIP + ENC28J60 (Ethernet module).
STM32F103C8T6 controller and compiler Keil.
I'm using some code Josef Gajdusek (atalax) of https://github.com/atalax/reflow-controller
What is working:
SPI communication with ENC28J60 works correctly (main/enc.c).
uIP handles packages responds to Ping and displays HTML + CSS + JS on http-request (main/http.c).
ChibiOS has two threads:
- Connected to the network,
- Blinker with reinitialization SPI and ENC on the button.
I have the following problem.
- Usually when a large traffic (hundreds and more Ping per second), network_thread freezes (stops and process packets from the network), but ThreadBlink keeps flashing LED. If you then press a button and ThreadBlink reinitialize SPI and ENC, then ThreadBlink stop flashing immediately.
- Can freeze both at the same threads.

Freeze, system reside in _idle_thread, forever.
This may work for 1 minute or 1 hour, but in the end anyway stop. Only helps restart.
I guess I somehow wrong manages the threads that they stop working.

You can look at the code:
https://github.com/JonBAL/STM32-ChibiOS-uIP-ENC28J60

Code: Select all

#include "main.h"
#include "stm32f10x.h"

#include "ch.h"
#include "hal.h"

#include "enc.h"
#include "uip.h"
#include "uip_arp.h"

#include "evtimer.h"

// Указатель на поток
Thread *tp = NULL;
Thread *tp2 = NULL;

// Структура связи с ENC60J28
struct enc encST = {
   &SPID1,
   {
      NULL,
      GPIOA,
      GPIOA_ENC_CS,
      SPI_CR1_BR_0 | SPI_CR1_BR_1
   },
   (uint8_t) 0,
   (uint16_t) 0,
   {
   ETHADDR0, ETHADDR1, ETHADDR2, ETHADDR3, ETHADDR4, ETHADDR5
   }
};

static const struct uip_eth_addr macaddr = {
   {ETHADDR0, ETHADDR1, ETHADDR2, ETHADDR3, ETHADDR4, ETHADDR5}
};

static EVENTSOURCE_DECL(enc_int_es);

static void enc_int(EXTDriver *drv, expchannel_t c)
{
   (void)drv;
   (void)c;
   chEvtBroadcast(&enc_int_es);
}

static const EXTConfig extcfg = {
   {
      {EXT_CH_MODE_DISABLED, NULL},
      {EXT_CH_MODE_FALLING_EDGE | EXT_MODE_GPIOA | EXT_CH_MODE_AUTOSTART, enc_int},
      {EXT_CH_MODE_DISABLED, NULL},
      {EXT_CH_MODE_DISABLED, NULL},
      {EXT_CH_MODE_DISABLED, NULL},
      {EXT_CH_MODE_DISABLED, NULL},
      {EXT_CH_MODE_DISABLED, NULL},
      {EXT_CH_MODE_DISABLED, NULL},
      {EXT_CH_MODE_DISABLED, NULL},
      {EXT_CH_MODE_DISABLED, NULL},
      {EXT_CH_MODE_DISABLED, NULL},
      {EXT_CH_MODE_DISABLED, NULL},
      {EXT_CH_MODE_DISABLED, NULL},
      {EXT_CH_MODE_DISABLED, NULL},
      {EXT_CH_MODE_DISABLED, NULL},
      {EXT_CH_MODE_DISABLED, NULL},
      {EXT_CH_MODE_DISABLED, NULL},
      {EXT_CH_MODE_DISABLED, NULL},
      {EXT_CH_MODE_DISABLED, NULL}
   }
};

#define EVID_NET_INT         0
#define EVID_NET_PERIODIC      1
#define EVID_NET_ARP         2

static void network_send()
{
   if (uip_len <= UIP_LLH_LEN + 40)
      enc_packet_send(&encST, uip_len, uip_buf, 0, NULL);
   else
      enc_packet_send(&encST, 54, uip_buf,
            uip_len - UIP_LLH_LEN - 40, uip_appdata);
}
// -----------------------------------------------------------
// СЕТЬ
// -----------------------------------------------------------
static WORKING_AREA(network_wa, 512);
static msg_t network_thread(void *arg)
{
   uip_ipaddr_t ip = {0 , 0};
   EvTimer per_evt;
   EvTimer arp_evt;
   EventListener per_el;
   EventListener arp_el;
   EventListener int_el;
   
   eventmask_t event;
   int i;
   uint8_t flags;
   uint8_t count = 0;

   (void)arg;
   
   tp2 = chThdSelf();   

   evtInit(&per_evt, MS2ST(1000));
   evtInit(&arp_evt, S2ST(10));

   chEvtRegister(&per_evt.et_es, &per_el, EVID_NET_PERIODIC);
   chEvtRegister(&arp_evt.et_es, &arp_el, EVID_NET_ARP);
   chEvtRegister(&enc_int_es, &int_el, EVID_NET_INT);

   spiStart(&SPID1, &encST.config);

   enc_init(&encST);
   uip_init();
   uip_setethaddr(macaddr);
   //uip_ipaddr(ip, IPADDR0, IPADDR1, IPADDR2, IPADDR3);
   //uip_sethostaddr(ip);
   //-----------------------
   uip_ipaddr(ip, 192,168,1,111);
   uip_sethostaddr(ip);
   uip_ipaddr(ip, 192,168,1,100);
   uip_setdraddr(ip);
   uip_ipaddr(ip, 255,255,255,0);
   uip_setnetmask(ip);
   //-----------------------
   uip_listen(HTONS(80));
   
   evtStart(&per_evt);
   evtStart(&arp_evt);

   while (1)
   {
      if (!palReadPad(GPIOA, GPIOA_ENC_INT))
      {
         event = EVENT_MASK(EVID_NET_INT);
      }
      else
      {
         chSysLock();
            palClearPad(GPIOB, GPIOB_PIN0);
            event = chEvtWaitAny(ALL_EVENTS);
            palSetPad(GPIOB, GPIOB_PIN0);
         chSysUnlock();
      }
      
      if (event == EVENT_MASK(EVID_NET_INT))
      {
         /* The interrupt line is low for as long as we have packets pending */
         flags = enc_int_flags(&encST);
         if (flags & ENC_PKTIF)
         {
            while ((uip_len = enc_packet_receive(&encST, UIP_BUFSIZE, uip_buf)) != 0)
            {
               switch(ntohs((((struct uip_eth_hdr *)&uip_buf[0])->type)))
               {
               case UIP_ETHTYPE_IP:
                  uip_arp_ipin();
                  uip_input();
                  if (uip_len > 0)
                  {
                     uip_arp_out();
                     network_send();
                  }
                  break;
               case UIP_ETHTYPE_ARP:
                  uip_arp_arpin();
                  if (uip_len > 0)
                  {
                     network_send();
                  }
                  break;
               default: /* This usually happens on overflows, hackish but works */
                  enc_init(&encST);
                  chSysLock();
                     palTogglePad(GPIOB, GPIOB_PIN1);
                  chSysUnlock();
                  break;
               }
            }
         }
         enc_int_clear(&encST, ENC_ALLIF);
         /* TODO: This patches the race condition, fix... */
         chThdSleepMicroseconds(100);
      }
      else if (event == EVENT_MASK(EVID_NET_PERIODIC))
      {
         for (i = 0; i < UIP_CONNS; i++)
         {
            uip_periodic(i);
            if (uip_len > 0)
            {
               uip_arp_out();
               network_send();
            }
         }
      }
      else
      {
         uip_arp_timer();
      }
      
      count++;
      if (count == 10)
      {
         count = 0;
         chSysLock();
         palTogglePad(GPIOB, GPIOB_PIN2);
         chSysUnlock();
      }
   }
}
// -----------------------------------------------------------
// МИГАЛКА
// -----------------------------------------------------------
static WORKING_AREA(waThreadBlink, 128);
static msg_t ThreadBlink(void *arg)
{
   while (1)
   {
      chSysLock();
      palTogglePad(GPIOB, GPIOB_PIN7);
      
      if (palReadPad(GPIOA, GPIOB_PIN15) == 1)
      {
         
            palTogglePad(GPIOB, GPIOB_PIN5);
            spiStop(&SPID1);
            spiStart(&SPID1, &encST.config);
            enc_init(&encST);
      }
      chSysUnlock();
      
      chThdSleepMilliseconds(200);
   }
}
// -----------------------------------------------------------
int main(void)
{
   halInit();
   chSysInit();

   spiInit();
   extInit();

   chEvtInit(&enc_int_es);
   extStart(&EXTD1, &extcfg);

   chThdCreateStatic(network_wa, sizeof(network_wa), NORMALPRIO, network_thread, NULL);
   chThdCreateStatic(waThreadBlink, sizeof(waThreadBlink), NORMALPRIO, ThreadBlink, NULL);

   while (1)
   {
      chThdSleepMilliseconds(500);
   }
}
User avatar
Giovanni
Site Admin
Posts: 14892
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: STM32+uIP+ENC28J60

Post by Giovanni »

Hi,

Do you have all the debug options enabled in chconf.h? it is possible those could catch some error.

Giovanni
JonBAL
Posts: 3
Joined: Sun Jan 04, 2015 5:03 pm

Re: STM32+uIP+ENC28J60

Post by JonBAL »

I'll try enable DBG (all DBG options - TRUE), and now I have an error at the start.
int main (void) - performed well.
First start network_thread, and start initialization.
Successfully comes to function chEvtRegister (& per_evt.et_es, & per_el, EVID_NET_PERIODIC); but during this execution ...

Code: Select all

void chEvtRegisterMask(EventSource *esp, EventListener *elp, eventmask_t mask) {
  chDbgCheck((esp != NULL) && (elp != NULL), "chEvtRegisterMask");

  chSysLock();
  elp->el_next     = esp->es_next;
  esp->es_next     = elp;
  elp->el_listener = currp;
  elp->el_mask     = mask;
  elp->el_flags    = 0;
  chSysUnlock();
}

at start chSysLock (); I have chDbgPanic ("SV # 4");.
JonBAL
Posts: 3
Joined: Sun Jan 04, 2015 5:03 pm

Re: STM32+uIP+ENC28J60

Post by JonBAL »

I use the following construction:

Code: Select all

int main(void)
{
   halInit();
   chSysInit();
   ...
   chThdCreateStatic(network_wa, sizeof(network_wa), NORMALPRIO, network_thread, NULL);
   chThdExit(0); // include chSysLock(); but not chSysUnlock(); (dbg_lock_cnt=1)
   while (1){}
}
static WORKING_AREA(network_wa, 512);
static msg_t network_thread(void *arg)
{
   ...
   chSysLock(); // And here I am SV # 4 because (dbg_lock_cnt! = 0)
   ...
   chSysUnlock();
   ...
}

Maybe it is a bug?
User avatar
Giovanni
Site Admin
Posts: 14892
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: STM32+uIP+ENC28J60

Post by Giovanni »

Hi,

chThdExit() causes a context switch, the decrement of dbg_lock_cnt is performed "on the other side" by the thread being switched in.

About SV#4, it is caused by a call to chSysLock() after another chSysLock(), there must be something not immediately visible in your code.

Giovanni
GunterO
Posts: 24
Joined: Tue Feb 03, 2015 9:59 am

Re: STM32+uIP+ENC28J60

Post by GunterO »

Hello,

I wonder if you found a working solution?
Thanks.
Post Reply