Antecedentes :
Engenheiro eletrônico Júnior de P&D ( o único EE da empresa ) - o hardware e a codificação não são o problema. Meu maior problema é obter uma visão geral adequada do projeto e por onde começar.
Até agora, fiz apenas pequenos projetos de software (menos de 500 linhas de código), mas não consigo me imaginar fazendo projetos maiores sem perder a visão geral da funcionalidade ou a falta de funcionalidade.
Como você estrutura melhor / quais ferramentas você usa para estruturar grandes sistemas de software embarcados?
O que estou fazendo atualmente :
Normalmente começo esboçando a funcionalidade do projeto. Pode ser um a muitos fluxogramas em camadas ou diagramas relacionados (diagramas de blocos, etc.) e fazer algumas pesquisas sobre os componentes / chips. Depois, passo direto para a codificação (acho que falho rápido) enquanto faço referência às planilhas de dados / Internet, codificando uma funcionalidade de cada vez e testando-a com dados fictícios ou teste semelhante. Pode estar gravando dados em um chip MEM e, se isso funcionar, pode ser um driver SPI entre o chip principal e o chip MEM.
Qual resposta estou procurando :
Qualquer coisa, mesmo. Vou resolver o que acho sensato. Pode ser um livro, um artigo, experiência pessoal, recomendações, etc.
Estou muito interessado em saber como os idosos lidam com isso.
Editar
Primeiramente, obrigado por compartilhar seus anos de experiência! Todas as respostas são muito apreciadas. Minha opinião disso é;
- Crie um documento de especificação claro e preciso.
- Crie um documento de design de software. (Algo que adicionarei agora) Modelos de documentos de design
- Pense nos módulos o quão redundante isso pode parecer. (Algo que eu preciso focar mais)
- Siga um padrão de codificação para estruturar arquivos de cabeçalho / fonte. (Nunca fiz isso) Padrão Barr Grupo C
- Concentre-se em criar as implementações de baixo nível primeiro. (Comunicação etc.)
- Implemente padrões de design sempre que possível / sensato. Padrões de design
- Configure algo para o controle de revisão (Github etc. - nunca usei tanto)
- Pesquise integração contínua / implantação contínua (algo de novo que eu me deparei) CI básico e CD
fonte
Respostas:
Existem vários aspectos que influenciam no grau de detalhe que a estruturação das necessidades de um projeto. Para mim, um dos principais fatores é se eu sou o único código (o que parece ser o seu caso enquanto você escreve, você é o único EE) ou se há outros envolvidos. Depois, há a questão do que "grande" realmente significa. Normalmente, divido o processo de design nas seguintes etapas:
Definição de requisitos Se você obtiver especificações de software adequadas para trabalhar com muito planejamento, já está feito. Se você receber requisitos vagos, a primeira coisa a fazer é resolver o que o cliente realmente deseja (às vezes, na verdade, ele não sabe). Eu sei que é tentador simplesmente pular direto para a codificação, mas isso traz o risco de perder um recurso importante que pode não ser óbvio em primeiro lugar e não pode ser facilmente espremido em seu código apenas em algum lugar no meio do desenvolvimento.
Limites do sistema e capacidade de manutenção Em sistemas embarcados, muitas vezes você tem algumas interfaces de sistema, algumas para o exterior (operador), mas também para o interior. Defina isso bem e tente manter as dependências o mais baixo possível, isso simplificará a engenharia e a manutenção contínuas. Além disso, comente / codifique o código quando necessário, você nunca sabe quem mais terá que trabalhar com ele; ele ficará feliz em não ter que cavar uma dúzia de camadas de código antes de realmente saber o que uma função faz.
Definir tarefas verificáveis Especialmente se outros desenvolvedores estiverem trabalhando na mesma base de código, é inevitável definir tarefas claras (recursos) e as interfaces necessárias entre eles. Sempre que possível, os recursos individuais devem ser testados / verificados independentemente dos outros, é aí que você precisa das interfaces bem definidas para poder definir seus casos de teste.
Um recurso após o outro As pessoas gostam de progresso, por isso, se você tiver uma variedade de tarefas, elas geralmente trabalham com o que promete mais progresso. Normalmente, tento concluir uma tarefa e trazê-la para um estado verificado e testado antes de começar a próxima. Isso permite que seu código seja testado por outras pessoas e você não acaba esquecendo algo.
Controle de revisão Durante a vida de um projeto, você às vezes precisa de versões mais antigas, talvez para identificar um bug introduzido em alguma nova versão ou apenas para criar um dispositivo que se comporte exatamente da mesma maneira que o que você enviou há 3 anos. Verifique se você possui revisões e tags de compilação claras no seu código. Git é definitivamente seu amigo aqui.
fonte
Humpawumpa escreveu uma ótima resposta ! Eu só quero complementar alguns de seus pontos, mas como isso é muito longo para ser um comentário, escreverei uma resposta separada.
Eu já estive na posição do OP - não o único EE, mas o único EE que havia feito algum desenvolvimento de MCU em uma pequena empresa.
Não posso enfatizar a importância da modularidade o suficiente, mesmo que você seja o único desenvolvedor. É a única maneira de manter a sanidade à medida que o projeto cresce. Você precisa ser rigoroso ao escrever módulos que lidam com apenas um conceito funcional cada um e manter suas interfaces externas o mínimo possível. Os módulos de alto nível corresponderão aos requisitos funcionais, enquanto os de baixo nível terão laços estreitos com os recursos de hardware (por exemplo, drivers de dispositivo).
Passei muito tempo mantendo um diagrama de fluxo de dados detalhado 1 , que mostrava exatamente como os vários módulos compartilhavam informações. Alguns recursos terão requisitos muito diferentes em termos de desempenho em tempo real; saiba como o compartilhamento de informações afeta isso. O diagrama tinha limites traçados através dele que separavam o código de não interrupção dos vários domínios acionados por interrupção.
1 Muito diferente de um fluxograma, focado no controle de fluxo.
fonte
Para qualquer projeto grande, planejo como se houvesse vários desenvolvedores envolvidos, mesmo que eu pretenda fazer tudo sozinho.
Os motivos são simples:
1 Complexidade. Um grande projeto sempre terá complexidades envolvidas. Planejar o projeto como se houvesse várias equipes envolvidas significa que a complexidade foi considerada e documentada . O número de vezes que vi grandes projetos encontrarem problemas é alto e geralmente porque algo "escapou". Não esqueça que a montagem mecânica também deve ser considerada e não apenas para o tamanho da caixa - haverá necessidade de dissipadores de calor? A caixa deve ser aterrada por segurança? Existem muitas perguntas somente nessa categoria.
2 Requisitos. Assumir que várias pessoas estão envolvidas significa que os requisitos de nível superior (que eu frequentemente desafio, pois podem trazer complexidade e custo desnecessários) devem ser divididos nas várias tarefas menores necessárias e realizáveis (que podem ser fornecidas a outra equipe em uma organização maior) ) em vez de apenas olhar para um único blob.
3 Particionando. Existem dois tipos principais de particionamento; funcionalidade de hardware e hardware / software. O primeiro tipo é determinar quais blocos funcionais separados (mas em comunicação) precisam estar presentes. O segundo é uma troca de hardware e software mais simples (às vezes), mas lembre-se de que simplesmente mover mais coisas para o software não necessariamente corrige um problema de hardware. Mover-se mais para o software pode realmente aumentar bastante a complexidade do hardware em algumas circunstâncias (mais potência de processamento, interfaces mais complexas e mais).
4 interfaces. O processo de particionamento ajudará a definir interfaces internas; interfaces externas geralmente fazem parte dos requisitos gerais (embora nem sempre). Existem muitas maneiras pelas quais diferentes partes de um sistema cooperam, que podem ser um protocolo de comunicação complexo ou simplesmente uma sinalização boa / ruim.
5 Verificação. Essa é uma mistura de testes de baixo nível (para hardware e drivers) e nível do sistema. O fato de ter feito o projeto em blocos bem definidos permite uma verificação robusta (que pode ser por análise ou teste real e geralmente é uma mistura dos dois; as atualizações nos projetos podem usar argumentos de similaridade).
6 Padrões. Uso padrões de codificação e desenho como se fosse uma equipe maior. Eu uso os padrões de codificação do grupo Barr, pois eles não são muito onerosos, mas evitam que muitas classes de erros estejam no código. Para documentação de saída de PCB, sigo o IPC-D-326 (que chama o IPC-D-325), pois esse é um método comprovado de comunicar minha intenção aos fabricantes e montadores de PCB. Isso pode parecer estranho, mas ter a disciplina para seguir vários padrões significa que a qualidade é consistente.
7 Controle de versão. Uso controle de revisão para todas as partes do projeto (sistema, hardware, software. Mecânico, requisitos de teste - tudo). As ferramentas de CAD que uso são compatíveis com versões, assim como todos os softwares e ferramentas de construção de FPGA.
Trabalhei em muitos projetos incorporados (assim como muitas pessoas experientes por aqui) e os tamanhos das equipes variaram de 1 (eu) a dezenas (ou centenas em um conjunto específico de projetos) espalhados por várias disciplinas e, às vezes, outras áreas geograficamente remotas sites. Usar a mesma abordagem abrangente (que é conhecida por funcionar) significa que posso pegar uma tarefa específica em relativo isolamento e concluí-la e testá-la completamente como parte autônoma do projeto maior. Isso também significa que eu posso sugerir algumas coisas de vez em quando, se necessário.
Fazer todas essas coisas adiciona um pouco de tempo inicial, mas, em última análise, é uma rota mais rápida para sistemas embarcados complexos.
fonte
As outras respostas dão muitas ótimas dicas. Aqui estão duas que eu achei as mais importantes na minha carreira de desenvolvimento incorporado:
É isso que você precisa para desenvolver o estilo de "integração contínua" em sistemas embarcados. Sempre haverá uma quantidade de código muito ligada ao hardware para testes automáticos, mas tente minimizá-lo. Você pode ir muito longe usando dados simulados ou capturas de dados de hardware real, que são alimentados no sistema de teste.
fonte
Para adicionar às respostas existentes ...
Eu sempre começo de baixo para cima. No seu design de hardware, você sabe qual é a sua E / S. Comece criando módulos de driver que encapsulem essa E / S, para que seu código de alto nível não precise saber muito sobre o material de baixo nível.
Ao criar interfaces de baixo nível, é claro que você precisa de um equipamento de teste. Se você projetar isso para conectar ao PC desde o início (talvez com uma porta RS-232, talvez USB, talvez telnet por Ethernet), poderá manter essa interface de equipamento de teste no lugar ao criar seu aplicativo. Você pode continuar adicionando mais ganchos de equipamento de teste à medida que o aplicativo for modelando, e isso permitirá que você teste novamente seu código à medida que avança.
fonte
Eu costumo pensar em quatro perguntas. Os dois primeiros pertencem ao início de um projeto de sistemas, os dois próximos ao final.
Eles realmente querem o sistema? O sistema resolverá o problema dos clientes, na escala de tempo e custo que eles aceitarão? Um problema comum é a construção de sistemas que o cliente não utilizará.
Podemos realmente construir esse sistema? Será possível fornecer o desempenho necessário, precisão, uso de energia, ...?
Criar protótipos iniciais é uma boa maneira de responder a essas duas primeiras perguntas. A mitigação de riscos é extremamente importante nas fases iniciais.
As próximas duas perguntas são mais direcionadas para as fases posteriores do projeto:
estamos realmente terminados? Tudo projetado, codificado, testado, entregue
Eles realmente usam o sistema?
fonte